Gdy bot nie działa, odpowiedź prawie zawsze znajduje się w jego wyjściu. Pokażemy, gdzie je znaleźć, jak działa automatyczny restart, jak przechwytywać błędy w kodzie i co oznaczają najczęstsze komunikaty.
Czego potrzebujesz
- Bot Discord w StormHost (lub na własnym VPS)
- Dostęp do strefy klienta
- Bot napisany w Node.js; przykłady kodu są dla discord.js w wersji 14
- Około 15 minut
Gdzie znaleźć logi#
W strefie klienta otwórz Moje usługi, kliknij swojego bota i zostań w zakładce Konsola.
- Konsola pokazuje na żywo wszystko, co bot wypisuje:
console.log()iconsole.info()trafiają na standardowe wyjście,console.error()iconsole.warn()na wyjście błędów. Gdy aplikacja się zawiesi, zobaczysz tu jej wyjście (błąd z listą plików i linii, czyli stack trace). - Pod konsolą widzisz bieżące zużycie CPU, RAM, dysku i sieci.
- Przyciski Start, Restart i Stop znajdują się w zakładce Konsola, nad samą konsolą.
Tryb streamera
Konsola bota ukrywa adresy IP w wyjściu tylko wtedy, gdy włączony jest tryb streamera. Nie ukryje jednak za Ciebie tokenu ani haseł. Nigdy nie wypisuj ich do konsoli i nigdy nie udostępniaj zrzutu ekranu, na którym są widoczne. Więcej w poradniku Strefa klienta.
Logowanie do pliku#
Konsola pokazuje tylko najnowszą część wyjścia. Jeśli chcesz sprawdzić, co działo się w nocy, zapisuj ważne zdarzenia także do pliku. Prosty pomocnik dla CommonJS (require):
const fs = require('node:fs');
const path = require('node:path');
const util = require('node:util');
const slozka = path.join(__dirname, 'logs');
fs.mkdirSync(slozka, { recursive: true });
const soubor = fs.createWriteStream(path.join(slozka, 'bot.log'), { flags: 'a' });
function zapis(uroven, ...casti) {
const radek = `[${new Date().toISOString()}] ${uroven} ${util.format(...casti)}`;
(uroven === 'ERROR' ? console.error : console.log)(radek);
soubor.write(radek + '\n');
}
module.exports = {
info: (...c) => zapis('INFO', ...c),
warn: (...c) => zapis('WARN', ...c),
error: (...c) => zapis('ERROR', ...c),
};| Część | Co robi |
|---|---|
fs.mkdirSync(slozka, { recursive: true }) | Tworzy folder logs obok pliku, jeśli nie istnieje. |
createWriteStream(…, { flags: 'a' }) | Otwiera plik do dopisywania na końcu (a = append); stare wpisy zostają. |
new Date().toISOString() | Czas zdarzenia w UTC, na przykład 2026-10-01T18:04:12.345Z. |
util.format(...casti) | Łączy części komunikatu tak samo jak console.log. Dla błędu zapisuje też listę linii (stack trace), dla obiektu jego zawartość. |
console.error / console.log | Linia pojawia się także w konsoli. |
soubor.write(radek + '\n') | Zapisuje linię do logs/bot.log. |
Użycie w bocie: const log = require('./logger');, a potem log.info('Bot gotowy') lub log.error('Polecenie nie powiodło się:', chyba). Plik logs/bot.log możesz pobrać w zakładce Pliki. Co jakiś czas go usuń lub opróżnij, aby nie zapełnił dysku.
Automatyczny restart#
Gdy bot się zawiesi (proces kończy się błędem), uruchamia się ponownie automatycznie. Krótkiej przerwy często nawet nie zauważysz, ale błąd zobaczysz w wyjściu konsoli.
- Jeśli bot pada w kółko tuż po starcie, błąd jest w kodzie lub ustawieniach i restart go nie naprawi. Przeczytaj pierwszy błąd w wyjściu, popraw go i uruchom bota przyciskiem Start.
- Nie używaj
process.exit()w kodzie jako zwykłego sposobu zatrzymania bota. Bot ma działać bez przerwy. - Po przesłaniu nowego kodu lub zmianie zmiennych w zakładce Ustawienia użyj Restart; zmiany zaczynają obowiązywać dopiero po restarcie.
Przechwytywanie błędów, aby bot się nie zawieszał#
Node.js kończy proces przy każdym błędzie, którego nikt nie przechwyci. Dotyczy to także odrzuconego Promise bez catch (domyślne zachowanie od Node.js 15). Jeden błąd w jednym poleceniu może położyć całego bota. Dodaj do pliku głównego (na przykład index.js) te nasłuchiwacze:
const { Client, Events, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.on(Events.Error, (chyba) => console.error('Błąd klienta discord.js:', chyba));
client.on(Events.Warn, (zprava) => console.warn('Ostrzeżenie discord.js:', zprava));
client.on(Events.ShardError, (chyba) => console.error('Błąd połączenia z Discordem:', chyba));
process.on('unhandledRejection', (duvod) => {
console.error('Nieobsłużone odrzucenie promise:', duvod);
});
process.on('uncaughtException', (chyba) => {
console.error('Nieprzechwycony wyjątek, bot zostanie zakończony:', chyba);
process.exit(1);
});| Nasłuchiwacz | Kiedy się uruchamia | Po co go dodać |
|---|---|---|
Events.Error | Klient discord.js zgłasza błąd. | Bez nasłuchiwacza zdarzenie error kończy proces. |
Events.Warn | Klient zgłasza ostrzeżenie. | Ostrzega o problemie, zanim coś się zawiesi. |
Events.ShardError | Błąd połączenia z gateway Discorda (websocket). | discord.js łączy się ponownie sam; zobaczysz, dlaczego do tego doszło. |
unhandledRejection | Promise zakończył się błędem i nikt go nie przechwycił (brak await wewnątrz try albo brak .catch()). | Bot nie zawiesi się przez jeden zapomniany błąd, a Ty zobaczysz, skąd pochodzi. |
uncaughtException | Synchroniczny błąd, którego nic nie przechwyciło. | Wypisuje błąd i kończy bota. Po takim błędzie kontynuowanie nie jest bezpieczne; automatyczny restart uruchomi bota ponownie w czystym stanie. |
Błędy w poszczególnych poleceniach przechwytuj bezpośrednio w obsłudze interakcji, aby użytkownik dostał odpowiedź, a bot działał dalej:
const { Events, MessageFlags } = require('discord.js');
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
try {
await zpracujPrikaz(interaction);
} catch (chyba) {
console.error(`Polecenie /${interaction.commandName} nie powiodło się:`, chyba);
const odpoved = { content: 'Podczas wykonywania tego polecenia wystąpił błąd.', flags: MessageFlags.Ephemeral };
if (interaction.replied || interaction.deferred) {
await interaction.followUp(odpoved).catch(console.error);
} else {
await interaction.reply(odpoved).catch(console.error);
}
}
});isChatInputCommand()– obsługuje tylko polecenia slash.zpracujPrikaz(– Twoja funkcja z logiką polecenia.interaction) try { … } catch (chyba) { … }– błąd w poleceniu trafia docatchzamiast zawieszać bota.MessageFlags.Ephemeral– odpowiedź widzi tylko użytkownik, który uruchomił polecenie.interaction.replied || interaction.deferred– jeśli bot już odpowiedział lub odroczył odpowiedź, kolejną wiadomość musi wysłać przezfollowUp, w przeciwnym razie przezreply..catch(console.error)– jeśli nawet odpowiedź o błędzie się nie powiedzie, zostanie tylko wypisana.
Pamięć#
Bot ma tyle RAM, ile zapewnia pakiet. Gdy jej zabraknie, zawiesza się (i restartuje automatycznie) albo znacznie zwalnia. Typowy komunikat przy awarii:
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memoryTen komunikat wypisuje sam Node.js, gdy zabraknie mu pamięci na obiekty JavaScript. Gdy proces zabija system z powodu limitu pamięci, wyjście może urwać się bez żadnego komunikatu o błędzie. W obu przypadkach warto sprawdzić, co zużywa pamięć (zobacz niżej).
Obserwuj zużycie pod konsolą albo niech bot sam je wypisuje:
setInterval(() => {
const mb = (b) => Math.round(b / 1024 / 1024);
const m = process.memoryUsage();
console.log(`Pamięć: łącznie ${mb(m.rss)} MB, sterta ${mb(m.heapUsed)}/${mb(m.heapTotal)} MB`);
}, 10 * 60 * 1000);process.memoryUsage()– bieżące zużycie procesu;rssto pamięć łącznie,heapUsedpamięć zajęta przez obiekty JavaScript.10 * 60 * 1000– wypisuje co 10 minut (wartość w milisekundach).
Jeśli pamięć stale rośnie, najczęstsze przyczyny to:
| Przyczyna | Rozwiązanie |
|---|---|
| discord.js trzyma w pamięci wiadomości, członków i inne obiekty (cache). Na dużych serwerach to dziesiątki tysięcy elementów. | Ogranicz cache i pozwól na usuwanie starych elementów (przykład niżej). Nie włączaj intentu GuildMembers, jeśli go nie potrzebujesz, i nie pobieraj wszystkich członków (guild.members.fetch()) bez powodu. |
| Własne tablice lub mapy, które tylko rosną (historia, cooldowny, buforowane wyniki). | Usuwaj stare elementy albo przechowuj dane w bazie danych. |
setInterval lub nasłuchiwacze zdarzeń dodawane w kółko (na przykład wewnątrz obsługi polecenia). | Rejestruj nasłuchiwacze raz, przy starcie. |
Ograniczanie cache w discord.js:
const { Client, GatewayIntentBits, Options } = require('discord.js');
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
makeCache: Options.cacheWithLimits({
...Options.DefaultMakeCacheSettings,
MessageManager: 50,
}),
sweepers: {
...Options.DefaultSweeperSettings,
messages: { interval: 3_600, lifetime: 1_800 },
},
});makeCache: Options.– ogranicza rozmiar cache;cacheWithLimits({ … }) MessageManager: 50= maksymalnie 50 wiadomości na kanał....Options.– pozostałe cache zostają z ustawieniami domyślnymi.DefaultMakeCacheSettings sweepers.messages– co godzinę (interval: 3_600sekund) usuwa z cache wiadomości starsze niż 30 minut (lifetime: 1_800).
Niektórych cache nie ograniczaj
Dokumentacja discord.js ostrzega, że ograniczanie cache dla GuildManager, ChannelManager, GuildChannelManager, RoleManager i PermissionOverwriteManager nie jest wspierane i psuje funkcje biblioteki.
Jeśli po optymalizacji bot naprawdę potrzebuje więcej pamięci, przejdź na większy pakiet w zakładce Zmiana pakietu. Do końca okresu płacisz tylko różnicę; kroki znajdziesz w artykule Przedłużenie i upgrade.
Bot na własnym VPS#
Jeśli uruchamiasz bota na VPS, skonfiguruj go jako usługę systemd. Zyskasz automatyczne restarty i uruchamianie po restarcie VPS, a logi trafią do dziennika systemowego (journalctl -u <NAZWA_USLUGI> -f). Kroki: Aplikacja działająca 24/7 z systemd.
Rozwiązywanie problemów#
Error: Cannot find module 'discord.js'#
Pakiety nie są zainstalowane (brakuje folderu node_modules albo nie ma w nim pakietu). Sprawdź, czy w katalogu głównym projektu jest package.json z discord.js w dependencies. Jak instalowane są pakiety na naszych serwerach, opisuje poradnik Przesyłanie i uruchomienie bota.
Error: Cannot find module '…/index.js' lub './commands/ping.js'#
Node.js nie znalazł pliku pod tą ścieżką:
- Plik główny ma inną nazwę albo leży w innym podfolderze, niż oczekują ustawienia uruchamiania.
- Wielkość liter: Windows jej nie rozróżnia, ale serwer Linux tak.
require(nie znajdzie na serwerze folderu'. /Commands/ ping. js') commands. Ujednolić nazwy. - Ścieżka względna jest liczona od pliku zawierającego
require, a nie od folderu, w którym bot startuje. Użyjpath.join(__dirname, …).
Error [ERR_REQUIRE_ESM]: require() of ES Module … not supported#
Wczytujesz przez require() pakiet, który istnieje tylko jako moduł ES (na przykład nowsze wersje niektórych bibliotek). Rozwiązania:
- Przełącz projekt na moduły ES (
import), zobacz następny błąd. - Albo wczytaj pakiet dynamicznie:
const { default: library } = await import('nazwa-pakietu');. - Albo użyj starszej wersji pakietu, która nadal wspiera CommonJS.
Nowsze wersje Node.js (20.19 i 22.12 oraz nowsze) potrafią wczytywać moduły ES przez require() i zgłaszają ten błąd tylko w starszych wersjach. Dla modułów z await na najwyższym poziomie zgłaszają ERR_REQUIRE_ASYNC_MODULE. Jak sprawdzić, której wersji Node.js używa Twój bot, opisuje sekcja Wersja Node.js.
ReferenceError: require is not defined in ES module scope, you can use import instead#
Projekt jest skonfigurowany jako moduły ES ("type": "module" w package.json albo plik z rozszerzeniem .mjs), ale kod używa require(). Albo przepisz require na import (import { Client } from 'discord.js';), albo usuń "type": "module" z package.json. W modułach ES nie działa też __dirname; użyj import.meta.dirname (Node.js 20.11 i nowsze).
SyntaxError: Cannot use import statement outside a module#
Odwrotność poprzedniego błędu: kod używa import, ale projekt jest CommonJS (zazwyczaj "type": "commonjs" w package.json). Dodaj "type": "module" do package.json albo użyj require(). Nie mieszaj obu w jednym projekcie.
SyntaxError: Unexpected token (na przykład '?' lub '.')#
Kod używa składni, której wersja Node.js na serwerze jeszcze nie wspiera. Sprawdź wersję (console. na początku bota) i porównaj ją z wymaganiami swoich bibliotek: discord.js 14 wymaga Node.js 18 lub nowszego. Kroki: Wersja Node.js.
Error: Used disallowed intents#
Bot żąda uprzywilejowanego intentu, który nie jest włączony w Discord Developer Portal. Otwórz Developer Portal (otwiera się w nowym oknie), swoją aplikację i sekcję Bot, a w Privileged Gateway Intents włącz to, czego bot faktycznie używa (Presence Intent, Server Members Intent, Message Content Intent). Albo usuń intent z kodu. Szczegóły: Token i intenty.
An invalid token was provided. (TokenInvalid)#
Token jest błędny, został unieważniony (po Reset Token w Developer Portal) albo nigdy nie został wczytany do bota (zmienna środowiskowa jest pusta, brakuje pliku .env albo nie jest wczytywany). Aby to sprawdzić, wypisz tylko długość tokenu, nigdy cały token: console.log('Długość tokenu:', process.. Użyj nazwy zmiennej, którą masz w kodzie. Kroki: Token i intenty.
DiscordAPIError[50013]: Missing Permissions#
Bot nie ma uprawnienia do danej akcji (wysłanie wiadomości, dodanie roli, usunięcie wiadomości, ban):
- Sprawdź role bota w ustawieniach serwera Discord oraz uprawnienia na tym kanale (kanał może nadpisywać uprawnienia).
- Kolejność ról: bot może zarządzać tylko rolami, które na liście ról są poniżej jego najwyższej roli. Przeciągnij rolę bota wyżej.
- Bot w żaden sposób nie może modyfikować właściciela serwera.
DiscordAPIError[50001]: Missing Access#
Bot nie widzi kanału lub serwera: nie ma na kanale uprawnienia Wyświetlanie kanału, w ogóle nie ma go na serwerze albo rejestrujesz polecenia dla serwera o błędnym ID (bota na nim nie ma). Jeśli ktoś dawno temu zaprosił bota tylko ze scope bot, a rejestracja poleceń wciąż się nie udaje, zaproś go ponownie linkiem ze scopes bot i applications.commands.
DiscordAPIError[10062]: Unknown interaction#
Na interakcję (polecenie slash, przycisk) trzeba odpowiedzieć w ciągu 3 sekund. Gdy polecenie trwa dłużej (baza danych, API), na samym początku wywołaj await interaction., a wynik wyślij później przez interaction.editReply(…). Odroczona odpowiedź pozostaje ważna przez 15 minut.
Ten sam błąd (albo DiscordAPIError[40060]: Interaction has already been acknowledged) pojawia się także wtedy, gdy działają dwie kopie bota z tym samym tokenem, na przykład jedna na naszych serwerach, a druga na Twoim komputerze. Obie próbują odpowiedzieć. Zostaw uruchomioną tylko jedną.
ECONNRESET, ETIMEDOUT, EAI_AGAIN#
Chwilowa awaria sieci albo zerwane połączenie z Discordem. discord.js sam łączy się ponownie z gateway i kilkakrotnie ponawia nieudane żądania REST API. Jeśli błąd powraca przez dłuższy czas, sprawdź nasz status usług i status Discorda (discordstatus.com (otwiera się w nowym oknie)).
Bot jest wolny, a w wyjściu pojawia się 429 lub rate limit#
Discord ogranicza liczbę żądań (globalnie 50 na sekundę na bota, plus inne limity dla poszczególnych akcji). Po przekroczeniu limitu discord.js automatycznie czeka i wysyła żądanie później, dlatego bot „zwalnia”. Nie wysyłaj wiadomości, ról ani edycji hurtowo w pętli.
Powtarzające się błędne żądania = blokada adresu IP
Gdy bot wyśle 10 000 błędnych żądań w ciągu 10 minut (odpowiedzi 401, 403 lub 429), Discord tymczasowo blokuje adres IP. Zazwyczaj powoduje to pętla, która w kółko próbuje wykonać akcję bez uprawnień albo z błędnym tokenem. Taki błąd napraw od razu, nie restartem.
Bot jest online, ale nie reaguje na wiadomości#
Aby czytać treść wiadomości (messageCreate i message.content), bot potrzebuje w kodzie intentów GuildMessages i MessageContent oraz włączonego Message Content Intent w Developer Portal. Bez niego message.content jest puste. Do poleceń używaj zamiast tego poleceń slash, które nie potrzebują tego intentu (pierwszy bot discord.js).
Bot jest offline#
- Spójrz na zakładkę Konsola: bot działa czy jest zatrzymany? Jeśli jest zatrzymany, uruchom go przyciskiem Start.
- Jeśli startuje i od razu pada, przeczytaj pierwszy błąd w wyjściu i odszukaj go wyżej.
- Jeśli działa bez błędów, ale jest offline, sprawdź token (po zresetowaniu tokenu stary przestaje działać i bot nie może się zalogować).
Nic nie pomogło: kiedy skontaktować się z pomocą techniczną#
Skontaktuj się z nami (kontakt), gdy:
- konsola się nie ładuje albo przyciski Start i Restart nie reagują,
- bot nie uruchamia się nawet z minimalnym kodem, który działa gdzie indziej,
- potrzebujesz innej wersji Node.js lub więcej pamięci.
Prześlij nam nazwę lub ID usługi, czas wystąpienia problemu i dokładny komunikat błędu (tekst skopiowany z konsoli). Nigdy nie wysyłaj tokenu bota.
Podsumowanie
- Wyjście bota znajdziesz w zakładce Konsola; dla historii zapisuj je także do pliku.
- Bot po awarii restartuje się sam; jeśli pada tuż po starcie, poprawka jest w kodzie.
- Nasłuchiwacze
Events.ErroriunhandledRejectionoraztry/catchw poleceniach chronią bota przed zawieszeniem przez jeden błąd. Used disallowed intentsiTokenInvalidnaprawisz w Developer Portal,Missing Permissionsw rolach na serwerze Discord.Unknown interaction= spóźniona odpowiedź (użyjdeferReply) albo dwie działające kopie bota.