Troubleshooting
Find your symptom, check the cause, apply the fix. Logs are the first place to look. On a server, run ssh deploy@$SERVER, then cd /opt/dl-discord-bot && docker compose logs --tail 100 bot (add | grep <word> to filter). Locally, read the terminal where the bot runs. Messages in [brackets] such as [ask] or [tickets] name the feature that wrote the line. Most fixes that change a setting end with redeploy: edit .env, then run bash scripts/deploy.sh (see Turn a feature on or off).
Startup
Section titled “Startup”| Symptom | Likely cause | Fix |
|---|---|---|
Exits at once with Invalid environment: and a list | One or more variables are missing or invalid. | Fix each line listed. See Configuration. |
DISCORD_GUILD_ID: must be a Discord snowflake | A snowflake is Discord’s id format, 17 to 20 digits, and the value is not one. | Copy the server id again with Developer Mode on (see Discord application, step 7). |
DATABASE_URL: Invalid URL or DATABASE_URL_POOLED: Invalid URL | The value is empty or not a URL. | Paste the whole Neon connection string, including ?sslmode=require&channel_binding=require. |
ASK_ENABLED: Invalid option: expected one of ... (or any other switch) | A true or false variable holds something else. | Use true or false. |
REMINDER_ALLOWLIST.0: must be Discord snowflakes (the number is the position of the bad entry, from 0) | An entry is not a user id. | Use comma separated user ids only, each 17 to 20 digits (right-click a member with Developer Mode on and choose Copy User ID). |
REMINDER_LATE_LIMIT_MINUTES: REMINDER_LATE_LIMIT_MINUTES must be at least REMINDER_TICK_MINUTES or due reminders are silently dropped | Reminders are on and the late limit is smaller than the tick. | Set the late limit to at least the tick (defaults: tick 15, late limit 60), lower the tick, or set REMINDERS_ENABLED=false. |
Invalid environment: and a line starting PORT: or NODE_ENV: | The line is blank (PORT= or NODE_ENV=). These two do not fall back to the default when blank. | Remove the line or give it a value. |
Invalid environment: and a line starting ASR_HOSTS: | ASR_HOSTS lists the speech-to-text (ASR) servers that voice notes use. The JSON is malformed or empty, or an entry lacks model, an https url or a positive weight. The value is never printed. | Fix ASR_HOSTS, or leave it unset for the PlaySafe hosts. |
[app] fatal: and a stack | Startup threw, and the message says what. With meeting transcripts on, a database error while reading the summary channel name is fatal too. | Fix what the message names, then deploy again. |
[tickets] startup prune failed:, [meetings] prune failed:, errors mentioning meeting_transcripts or linear_link_source, or column ... does not exist | A migration has not been applied (0009 for tickets, 0010 for linear_link_source, the meeting tables for meetings). | Run the migrations (bash scripts/deploy.sh does it), then restart. |
| Container stops and does not come back | The restart policy gives up after 5 failed restarts. | Read docker compose logs bot, fix the cause, then run bash scripts/deploy.sh again. |
deploy.sh ends with ERROR: timed out waiting for bot to become healthy. | No health result within 120 seconds. Usually the bot is crashing at startup and restarting. | Read the 200 log lines it prints. Look for Invalid environment:, then check the token and intents. |
ERROR: bot reported unhealthy. | The health check failed 3 times in a row, so the bot has not finished logging in to Discord. | Read the 200 log lines it prints. Check the token and intents. |
/health answers 503 {"status":"starting"} | Discord login has not finished. | Wait, then check the token and intents if it stays that way. |
Discord
Section titled “Discord”| Symptom | Likely cause | Fix |
|---|---|---|
Used disallowed intents | A privileged intent is off. | Turn on Message Content and Server Members on the Bot page of the Developer Portal, see Discord application, then redeploy. |
Missing Access | The bot cannot see the channel or server. | Invite it again, or fix the channel permissions. |
| Slash commands do not appear | Commands are registered to one server only. | Check DISCORD_GUILD_ID is the right server. |
[backfill] cannot read: ... | The bot lacks View Channels or Read Message History on those channels. | Grant both on the channels you want stored. |
A member never gets a DM and the log says not delivered: dm_closed (Discord error 50007) | The member turned off DMs from server members. | Nothing to fix. The message is recorded as failed and not sent again. |
The log says not delivered: discord_<code> | Discord refused the DM for another reason; the code is Discord’s error code. | Look the code up in Discord’s error list. The message is recorded as failed and not sent again. |
A command or button answers Unknown command. or Unknown action. | The feature behind it is switched off. For example, buttons on /summary-admin messages stop working when SUMMARIES_ENABLED=false. | Switch the feature on again, or ignore the old message. |
A command or button answers Something went wrong. and the log has [router] error handling interaction: | The handler threw. | Read the lines above the log line. If it repeats, the cause is usually the database or Linear. |
[bot] command registration failed: and the bot exits | DISCORD_GUILD_ID is a server the bot is not in, or the invite lacked the applications.commands scope. | Fix the id or invite the bot again with both scopes. The bot exits on purpose rather than run half set up. |
[bot] session invalidated, exiting | Discord ended the bot’s session. The container restart policy starts it again. | If it repeats, check the token. |
[router] slow interaction pickup: /<command> after N ms | The bot received a slash command more than 1.5 seconds after Discord created it, and Discord drops an unacknowledged command after 3 seconds. The bot was busy, or the host’s network or clock was slow. | If Application did not respond follows, look for what held the bot up then: a restart, a long start, or a loaded host. Only the command name is logged. |
Database
Section titled “Database”| Symptom | Likely cause | Fix |
|---|---|---|
| Migration fails | DATABASE_URL is the pooled URL. | Use the direct Neon URL, whose host has no -pooler (see Create the database). |
[migrate] failed: Error: DATABASE_URL is not set | On a server, .env has no DATABASE_URL line. Locally, bun run db:migrate does not load .env. | Set it in .env. Locally run bun --env-file=.env run db:migrate. |
Migration fails creating the vector extension | The database user cannot create extensions. | Run CREATE EXTENSION IF NOT EXISTS vector; once in the Neon SQL editor, then migrate again. |
[db] pool error: | A connection dropped. The bot does not crash on it. | Check the pooled URL if it repeats. |
[db] warm-up failed: <class> at start | The bot could not open its three first connections. | Check DATABASE_URL_POOLED and that the database is reachable from the server. |
[search] semantic leg failed; using full-text only: | A search could not get its embedding, so it used word matching only. | Check GEMINI_API_KEY and quota. |
Server and deploy
Section titled “Server and deploy”| Symptom | Likely cause | Fix |
|---|---|---|
permission denied while trying to connect to the Docker daemon socket | The shell started before the docker group was added to the deploy user. | Log out, run ssh deploy@$SERVER again and check that id lists docker. |
Permission denied (publickey) on git clone or git fetch | The deploy key is not on the repository. | Run step 2 of Set up the server, then ssh deploy@$SERVER 'ssh -T git@github.com'. |
Host key verification failed | known_hosts on the server has no GitHub entry. | Run step 1 of Set up the server again. It is safe to repeat. |
env file /opt/dl-discord-bot/.env not found | The first deploy block has not run yet. | Run the block under First deploy. |
The Deploy job fails at the SSH step | A secret is missing or wrong. | gh secret list -R dogelabsvr/doge-discord-bot must show VPS_HOST, VPS_USER and VPS_SSH_KEY. Run the block under Deploy on every push again. |
Reminders
Section titled “Reminders”| Symptom | Likely cause | Fix |
|---|---|---|
The log says [reminders] disabled | REMINDERS_ENABLED is false. | Set it to true and redeploy. |
| Nobody gets reminders | The ready line shows an allowlist that excludes them. | Check allowlist N members in the [reminders] enabled line. An empty list means everyone. |
| The standup rule never fires | A channel rule with no channel is ignored. The shipped standup rule starts without one and fills itself only from a channel named stand-up (with a hyphen). | Name a channel stand-up, or set the channel by hand, for example /reminder-rules edit name:standup channel:#standup. See Reminder rules. |
| The art end-of-day rule never fires | It ships disabled and needs a channel. | Enable it and set a channel. |
| One member gets nothing | They have no timezone or working hours, their work day started on a Saturday or Sunday in their timezone (no channel reminders then), or they already posted. | Ask them to run /hours set with a timezone. |
| Members got a DM asking them to set their timezone and working hours | The setup DM: each member who has not set both gets it once, up to 25 per tick, and it follows the allowlist. | Expected. Set REMINDER_ALLOWLIST before the first start if you do not want everyone to get it. |
| Reminders missed after downtime | The bot was down longer than the late limit, so late channel reminders were skipped. | Raise REMINDER_LATE_LIMIT_MINUTES for more slack, up to 720, never below the tick. |
| A follow-up never arrives | The member is outside the allowlist, or has left the server. Those follow-ups are marked skipped. | Check the allowlist. |
| A follow-up arrives a few seconds late | Follow-ups have their own timer and are sent to the second, give or take a moment. One due while the bot was off is sent at the next start, however late. | None. |
| I tagged the bot and nothing happened | Reminders are off (and asking too, for a question), the author is not on REMINDER_ALLOWLIST (follow-ups only), the message tags a role other than the bot’s own or pings @everyone (Discord lists two entries with the bot’s name, the bot and its own role, and either works), or the model decided it was neither a follow-up request nor a question. | Check [reminders] enabled and the allowlist. Ask the member to say what they want, for example remind me in 2 hours, or to reply to a message and tag the bot. |
| I tagged the bot and it did not reply in the channel, but the follow-up is saved | The bot lacks Send Messages in that channel. | Give it Send Messages (and Send Messages in Threads for threads). |
| I tagged the bot with a question and got no reply | Asking is off or has no GEMINI_API_KEY, the model read it as a follow-up or as neither, the message had only the mention, the 20 readings per hour or the MENTION_MAX_CHECKS_PER_DAY readings were used up, the bot lacks View Channel, Send Messages, Embed Links or Read Message History in the channel, or the message was deleted. | Check [ask] enabled in the logs. Ask the member to use /ask, which needs none of the above. |
| The bot reacted to my tag with an hourglass | The member already has a question being answered, or a refusal was due and the member had already been told once this hour. Later refusals only react. | Wait for the first answer. |
The bot answers a tag with Keep questions under 500 characters, or use /ask. | The question is longer than 500 characters. | Shorten it, or use /ask. |
| Tagging the bot on a plain message does nothing, and tagging it on a reply asks for a time | There is no GEMINI_API_KEY, the member has used 20 readings in the hour, the day’s MENTION_MAX_CHECKS_PER_DAY readings are used up, or the call failed. The bot then treats a tag on a reply as a follow-up with no time and ignores any other tag. | Set the key, or wait for the hour or the day to pass (a restart clears the daily count). A failed reading logs [follow-up] mention reading failed: <error class>. |
See The reminder engine for the exact timing rules.
Summaries
Section titled “Summaries”| Symptom | Likely cause | Fix |
|---|---|---|
/summary, /interests and /summary-admin do not appear | SUMMARIES_ENABLED is off, which is the default. The commands are registered only when it is on. | Set it to true and redeploy. The log shows [summaries] enabled instead of [summaries] disabled. |
[summaries] AI is not configured, scheduler idle or /summary now says Summaries are not available: AI is not configured. | No GEMINI_API_KEY. Nothing is sent until it is set. | Set it and redeploy. |
[summaries] daily generation cap reached or Daily summary limit reached, try again later. | SUMMARY_MAX_GENERATIONS_PER_DAY summaries were sent or failed in the last 24 hours, counted per recipient. | Wait, or raise the limit, up to 10000. A scheduled summary is retried only for 60 minutes after its send time. |
Please wait N seconds before asking for another summary. /summary now and /interests now share this limit. | /summary now and /interests now share a 60 second cooldown per member. It is kept once generation started and released when the command stops early. | Wait and ask again. |
Busy right now, try again shortly. | Three on-demand summaries are already running. | Try again in a moment. |
You can ask for 5 on-demand digests per day. Try again later or wait for your digest. | /interests now is limited to 5 runs per member per rolling 24 hours. | Wait for the scheduled digest. |
Linear is not connected, so I cannot validate the team. Ask an admin to set LINEAR_API_KEY. | LINEAR_API_KEY is unset. /summary-admin create and /summary-admin map-channel refuse to run without it. | Set it and redeploy, then run the command again. Existing summaries keep working from messages alone. |
| A recipient gets no scheduled summary | They are outside REMINDER_ALLOWLIST, have no timezone, or cannot see any mapped channel. Daily summaries also skip Saturday and Sunday in the recipient’s timezone, and one more than 60 minutes late is dropped, so downtime across the send time loses it. | Check the allowlist, ask them to run /hours set with a timezone, and check the channel count for that summary’s team with /summary-admin list. In the tick line [summaries] tick: sent=... failed=... skipped=... notimezone=..., skipped counts recipients who can see no mapped channel and notimezone those with no timezone. Members outside the allowlist are not counted. |
| Every summary fails | Gemini rejected the call, or its quota is used up. | Check GEMINI_API_KEY and your quota. [summaries] generation failed for <name>: ... gives the error, never message text or the prompt. A successful run logs [summaries] generated <name> group=N in=... out=... ms=..., token counts only. |
See Summaries for how a summary is built and Summary configs to manage them.
Asking questions
Section titled “Asking questions”| Symptom | Likely cause | Fix |
|---|---|---|
/ask does not appear, or the log says [ask] disabled or [ask] off: needs GEMINI_API_KEY | ASK_ENABLED is off (the default), or there is no GEMINI_API_KEY. The command is registered only when both are set. | Set what is missing and redeploy. |
Asking is not set up yet. Ask an admin. | The Gemini key was removed after the command was registered. | Set GEMINI_API_KEY and redeploy. |
I am still answering your last question. | A member can have one question running at a time. | Wait for the answer. |
Busy right now, try again shortly. | Four questions are already running across the server. | Try again in a moment. |
That took too long to search. Try a shorter period or a more specific question. | The search ran out of time. | Ask for a shorter period or something more specific. |
I could not find anything you have access to search. | The member can view none of the stored channels, so there was nothing to search. | Check the member’s Discord permissions. |
You have asked N questions in the last 24 hours. Try again later. or The daily question limit is reached. Try again later. | ASK_MAX_PER_MEMBER_PER_DAY or ASK_DAILY_CAP was reached. A failed question counts too. | Wait, or raise the limit and redeploy. |
I could not check which channels you can see right now. Try again in a minute. and [ask] question ... failed scope_unavailable | Discord did not return the member’s channel permissions. No model call was made, but the question still counts. | Ask again shortly. |
Answers say I could not find that in what I can search. for things the member knows exist | The member cannot view the channel now, the meeting summary was posted in a channel they cannot view, the answer is public and the source is not in a channel everyone there can read, or the channel is not stored yet. Linear issues are never searched. | Check the member’s Discord permissions. Try /ask without public to use everything they can see. |
I could not answer that right now. Try again in a minute. | The model failed or timed out. The log has [ask] question <id> failed: <error class>. | Check GEMINI_API_KEY and quota. |
An old Answer privately button says This button is no longer used. Ask with /ask or tag me. | The button is from a retired flow. | Ask again with /ask or by tagging the bot. |
See How asking works.
Ticket prompts
Section titled “Ticket prompts”| Symptom | Likely cause | Fix |
|---|---|---|
[tickets] disabled | TICKET_PROMPTS_ENABLED is false, which is the default. | Set it to true and redeploy. |
[tickets] off: needs GEMINI_API_KEY and LINEAR_API_KEY | The switch is on but a key is missing. Nothing is checked. | Set both and redeploy. |
| Nobody gets a prompt | The author is outside REMINDER_ALLOWLIST, the message has fewer than 8 words (links, emoji, mentions and code do not count), the author is a bot, or it is an edit or an old message from the backfill. Only new messages are checked. | Check allowlist N members in the [tickets] enabled line. Post a new message of 8 or more words that pitches a feature. |
| A member stopped getting prompts | They reached TICKET_PROMPT_DAILY_CAP in the last 24 hours. A prompt whose DM failed counts too. | Wait, or raise the cap, up to 50. |
| Prompts stopped for everyone | TICKET_PROMPT_MAX_CHECKS_PER_DAY is used up (checks are skipped without a log line), or Gemini is down (one log line, checks pause for a minute). | Raise the limit, up to 100000; a restart resets its count. For Gemini, look for [tickets] AI unavailable, pausing checks for 60 s and check the key and quota. |
[tickets] prompt not delivered: dm_closed (message ...) | The author turned off DMs from server members. | Nothing to fix. The prompt is not sent again. |
[tickets] no public Linear teams visible | The Linear key sees no public team. | Check the key’s access. Private teams are never searched, and are offered only to a linked member who belongs to them. |
A member’s ticket was not assigned to them, or [tickets] create retried without extras is in the log | Linear refused the assignee, a label or the cycle as invalid, so the bot filed the ticket without them. The reply said Filed in <team>. instead of Assigned to you in <team>., with a line such as Linear rejected some details, so it was filed without its assignee, labels or cycle. | Check the member’s link with /linear-admin list, and fix it with /linear-admin link. |
A ticket reply says <team> does not use cycles, so the ticket was filed without one., <team> has no current cycle, ..., <team> has no next cycle, ... or Could not read <team>'s cycles, ... | The member chose a cycle the team does not have, or Linear did not answer when the bot looked. The ticket is filed with no cycle. | Nothing to fix. Set the cycle in Linear, or check the team’s cycle settings. |
A ticket reply says Linear did not confirm this ticket's details, so check them in Linear. | An earlier attempt may have reached Linear, so the bot found the ticket by its id instead of creating it again. The team and cycle shown are not claimed. | Open the ticket in Linear and check it. |
Could not create the ticket in Linear, so nothing was filed. Your text is saved: press Create ticket to try again. | Linear failed for a reason that is not a timeout, a rejection of the key or invalid content. | Ask the member to press Create ticket again. |
[tickets] label pick failed: <name> or [tickets] label list failed: <name> | The model or Linear failed while choosing labels. The ticket was filed without labels. | Nothing to fix unless it repeats. Check GEMINI_API_KEY and the Linear key. |
[tickets] team suggestion failed: <name> | The suggestion call failed. The form opens with no team preselected. | Nothing to fix unless it repeats. Check GEMINI_API_KEY. |
[tickets] auto-link failed: <name> | The name match for one author failed when they submitted a form. The ticket was filed without an assignee. | Nothing to fix unless it repeats. Run /linear-admin sync. |
[linear] auto-linked N members, M unsure, K unmatched | The name match ran. Counts only. | Expected. Run /linear-admin list to see the unsure members. |
[linear] startup auto-link failed: ... | The name match at start could not reach Linear. Nothing was linked. | Run /linear-admin sync once Linear answers. |
/linear-admin is missing from the server | LINEAR_API_KEY is not set. The command follows the key, not TICKET_PROMPTS_ENABLED. | Set the key and redeploy. |
/linear-admin answers Could not reach Linear. Try again in a moment. | Linear did not answer, or rate limited the bot. | Try again. |
[tickets] duplicate of ... (message ...) | Linear already has a matching ticket, so no prompt was sent. | Expected. |
Linear rejected the ticket, so nothing was filed. Tell an admin: the bot may lack permission for that team. and a log line starting [tickets] create failed: auth or [tickets] create failed: invalid | With auth, the Linear key lacks Create issues or cannot file into that team. With invalid, Linear refused the ticket’s content or team. | For auth, fix the key. For invalid, ask the member to choose another team or change the text. Then they press Create ticket again; their text is kept. |
Linear is slow right now. Press Create ticket again in a moment. | The team list did not arrive in time. | Ask the member to press Create ticket again. |
Linear did not answer in time, so I cannot tell yet whether the ticket was filed. Press Create ticket to check: it will not create a second one. | Linear timed out after the request was sent. | Ask the member to press Create ticket again. It finds the ticket if it was made. |
Buttons answer Ticket prompts are turned off. | LINEAR_API_KEY is not set. | Set it and redeploy. |
[tickets] queue full, dropped N | A burst of messages filled the check queue. | Nothing to fix. Dropped messages are not retried. |
[tickets] check failed: ... | One check hit an error that was not a Gemini outage, for example Linear refused the search. The line gives the error type only. | If it repeats, check that LINEAR_API_KEY has Read. The message is not checked again. |
See Ticket prompts for how a prompt is decided.
Meeting transcripts
Section titled “Meeting transcripts”| Symptom | Likely cause | Fix |
|---|---|---|
[meetings] disabled | MEETING_TRANSCRIPTS_ENABLED is false, which is the default. | Set it to true and redeploy. |
[meetings] off: needs GEMINI_API_KEY | The switch is on but there is no Gemini key. Nothing is read. | Set it and redeploy. |
| Nothing happens when a file is uploaded | The upload is in a different channel, a thread or another server, the switch is off, there is no key, or the channel does not exist yet. Only the one text channel with the current summary channel name is watched, and the bot does not create it at startup. | Check the channel name against the log line [meetings] enabled, #<channel>. Create a text channel with that name by hand, or run /notes-admin summary-channel show. With voice notes on, the first voice meeting creates it. |
[meetings] channel create failed: <class> (with (code 50013) for a permission) or [meetings] channel lookup failed: <class> | The bot lacks Manage Channels, or Discord returned another error while listing or creating channels. | Create a text channel with the name by hand, or give the bot Manage Channels. The voice meeting that hit this keeps its summary in the voice chat. |
| The bot replies in the channel but sends no DM (and the Linear key is set) | The owner is outside REMINDER_ALLOWLIST, has DMs closed, or the DM failed. For the last two the reply says <names> could not get a DM (their DMs are closed), so their action items are only listed above. People the allowlist left out are not named. | Check the allowlist. A closed DM is recorded as dm_closed and not sent again. |
I could not update <ticket> because your Discord account is not linked to Linear yet. Ask an admin to run /linear-admin link for you. or ... because you are not on its Linear team. | Updating an existing ticket needs the person pressing the button to be linked to a Linear user by an admin (a name match does not count) and to be a member of the ticket’s team. The bot writes with its own key, so this check is what stops anyone from changing any ticket. | Link the member with /linear-admin link, or ask someone on that team to apply it. Nothing was changed. |
Could not find <ticket> in Linear, so nothing was changed. | The ticket was deleted or moved, or is in a private team, which the bot never changes. | Change it in Linear. |
Could not check your access in Linear, so nothing was changed. and [meetings] update check failed: <kind> (<name>) | Linear did not answer the membership check. | Press the button again in a moment. |
[meetings] update failed: auth or [meetings] update failed: invalid, and Linear rejected the update, so nothing was changed. | The key may not update issues or comment on that team, or Linear refused the change. | Fix the key’s permissions or the team, then press the button again. |
[meetings] update failed: timeout, and Linear did not answer in time, so the update may or may not have been applied. | Linear was too slow. The status may be set, or the comment may have been added. | Look at the ticket in Linear before pressing the button again, so a comment is not added twice. |
An update was added as a note and says (no "In Review" state, so I added a note instead) (or another status) | The ticket’s team has no workflow state matching the status the meeting named. The bot never guesses another state. | Add the state to the team’s workflow if you want it set. |
| An owner got nothing and the uploader got the item instead | The name in the meeting matched no member or more than one, so the item had no owner. The bot never guesses a person. | None. |
Meeting tickets are turned off. | LINEAR_API_KEY was removed after the message was sent. | Set it and redeploy. |
The AI service is unavailable right now. Please upload the file again in a minute. and [meetings] AI unavailable, pausing for 60 s | Gemini timed out, is rate limited or failing, or rejected the key. | Check GEMINI_API_KEY and your quota, then upload the file again after a minute. |
Please upload one file at a time. | The message had more than one attachment. | Upload one file per message. |
Please upload the transcript as a file (.txt, .vtt, .srt or .md) and I will summarise it, or run /notes start in a voice channel to take notes live. | Someone typed text in the meetings channel. The bot says this at most once an hour per member. | Upload the transcript as a file. |
You have uploaded a lot of files recently. Please try again later. | The member sent more than 10 uploads in an hour. | Wait an hour. |
I can only read .txt, .vtt, .srt, .md transcripts., That file is not plain text, so I cannot read it., That file has no text in it. or I could not download that file. Please upload it again. | The file has another extension, is binary, is empty, or Discord’s download failed. | Upload a text transcript again. |
That file is already being processed. | The same file is being read right now, or another upload of it holds the claim. | Wait for the summary. |
The daily limit for transcripts has been reached. Please try again tomorrow. | MEETING_MAX_PER_DAY transcripts were read in the last 24 hours. A run that ended because Gemini was down does not count. | Wait, or raise the limit, up to 1000. A restart resets the count. |
You have reached your daily limit of 5 transcripts. Please try again tomorrow. | That member uploaded 5 transcripts in 24 hours. The limit is fixed. | Wait, or have someone else upload. A restart resets the count. |
| Members got the summary but no action item messages | There is no LINEAR_API_KEY, the bot restarted between the post and the messages, or their DMs are closed. | Set the key. After a restart, upload the same file again two minutes after the post: the bot sends only the messages that had not gone out. |
That file is too large (the limit is 512 KB). | The file is over MEETING_MAX_FILE_KB, 512 by default. The reply gives KB below 1 MB and whole megabytes from 1 MB up. | Cut the transcript or raise the limit. |
I already summarised this file: [see the summary](...) or Already received this file. | The same file was already read. Files are matched by their content. | Expected. Follow the link. |
The summary ends with Only the first part of this transcript was read because it is too long. | The transcript is over 400,000 characters, so the rest was cut. | Split the transcript and upload the parts. |
The summary ends with N more lines not shown. | The summary is longer than four Discord messages. | None. |
[meetings] upload failed: <code> (<name>, meeting <id>) | The upload ended with a reason, such as ai_unavailable, not_text or generic. Class only, never the file text. | Upload the file again. If generic repeats, check the log lines above it. |
[meetings] create failed: auth or [meetings] create failed: invalid, and Linear rejected the ticket, so nothing was filed. Tell an admin: the bot may lack permission for that team. | With auth, the Linear key lacks Create issues or cannot file into that team. With invalid, Linear refused the ticket or the team. | For auth, fix the key. For invalid, ask the member to choose another team. Then press Create selected again. |
A meeting DM says Linear did not answer in time, so I cannot tell yet whether the ticket was filed. Try again in a moment: it will not create a second one. | Linear timed out after the request was sent. | Press Create selected again. It finds the ticket if it was made. |
[tickets] create retried without extras and a DM line such as Linear rejected some details, so 2 of 3 tickets were filed without their assignee or labels. | Linear refused the assignee, a label, the project or the cycle, so the bot filed the ticket without them. | Check the member’s link with /linear-admin list. |
[meetings] label list failed: <name>, or [tickets] label pick failed: <name> during a meeting ticket | The model or Linear failed while choosing labels. The ticket was filed without labels. | Nothing to fix unless it repeats. |
[meetings] queue full, dropped N | A burst of messages filled the queue. | Dropped uploads are not retried: ask the member to upload again. |
See Meeting transcripts for how a transcript is processed.
Voice notes
Section titled “Voice notes”| Symptom | Likely cause | Fix |
|---|---|---|
[voice] disabled | VOICE_NOTES_ENABLED is false, which is the default. | Set it to true and redeploy. |
[voice] off: needs MEETING_TRANSCRIPTS_ENABLED and GEMINI_API_KEY | The switch is on but meeting transcripts are off or there is no Gemini key. | Switch meeting transcripts on and set the key, then redeploy. |
/notes or /notes-admin does not appear | /notes needs voice notes on. /notes-admin needs meeting transcripts on (not voice notes). Or the bot has not restarted since the switch: commands are registered at start. | Check the [voice] and [meetings] lines. |
Join a voice channel first, then run /notes start. | The member is not in a voice channel. | Join one, then run the command. |
I am already taking notes in <channel>. Only one meeting at a time. | A session is running or starting. The channel is named only if the member can see it, else another channel. | Wait for it to end, or stop it with /notes stop. |
An admin has turned off notes in this channel. | The channel is excluded and the member does not have Manage Server. | An admin can /notes-admin include it. |
Ask an admin to give me Connect, View Channel and Send Messages in that channel. | The bot’s role lacks one of them in that channel, often because the voice channel is private. | Grant them to the bot’s role in that channel. |
I could not join that voice channel. Try again in a moment. and [voice] join failed: <class> | Discord did not complete the voice connection in 30 seconds. The server may block outbound UDP, or Discord had an issue. | Try again. If it repeats, check that the host allows outbound UDP. |
[voice] connection error: <class> | The voice connection reported an error. The bot logs it and carries on. | Nothing to fix unless meetings keep ending with I was disconnected from the voice channel. |
[voice] connection <from> -> <to>, [voice] ready after N ms or [voice] join did not become ready (last state <state>) after N ms: <class> | Each connection state change, how long the join took, and where a timed-out join got stuck. Names and timings only. | Read them when /notes start is slow or fails: a join that stops at signalling or connecting usually means the host blocks outbound UDP. |
I could not post the notice in the voice channel chat, so I did not start taking notes. Check my Send Messages permission there. and [voice] could not post in the channel chat: <class> | The bot lacks Send Messages in the voice channel’s text chat. It will not transcribe without the notice. | Grant it there. |
I lost the voice connection while joining. Try again in a moment. | The connection dropped before the notice was posted. | Try again. |
The transcription service was unavailable, so no notes were written. and [asr] <model> failed: status 5xx | Every host failed for every utterance. The fleet may be down or saturated (503). | Check the hosts and ASR_TIMEOUT_SECONDS, then take the meeting again. |
[voice] ASR unavailable, pausing: AsrUnavailableError and the voice chat says The transcription service is having trouble, so parts of this meeting may be missing from the notes. | Three utterances in a row failed on every host. Transcription paused for 30 seconds. | Nothing to fix if it passes. If it repeats, check the hosts. |
[voice] receive stream error: <class> | One speaker’s audio stream failed. That person may be missing from the notes for a while. | None. The bot listens again when they speak. |
There was too little speech (the transcript was too short), so no notes were posted. | Under 200 characters of text, or utterances shorter than VOICE_MIN_UTTERANCE_MS were dropped. | Talk longer, or lower VOICE_MIN_UTTERANCE_MS. |
| The summary is in the voice chat, not the shared channel | The voice channel is not open to everyone, so it goes to its own chat on purpose. Or the bot could not find or create the shared channel, and the notice said so. | Check @everyone has View Channel and Connect on the voice channel. For a missing channel, create it or give the bot Manage Channels. |
[voice] summary channel check failed: <class> | Looking up the shared channel raised an error. The summary stayed in the voice chat. | Check the log, then try again. |
[meetings] voice notes failed: <code> (<class>) | The write-up ended with a reason, such as ai_unavailable, daily_cap, uploader_cap or generic. The voice chat says why, and the starter is DMed unless the allowlist leaves them out. The limit messages are The daily limit for meeting notes has been reached. Try again tomorrow. and You have reached your daily limit for meeting notes. Try again tomorrow. | As for uploads, see Meeting transcripts. |
The AI service was unavailable, so the notes are not written yet. I kept what was said and will write them up automatically in a few minutes. | Gemini was down when the meeting ended. The transcript is saved and a sweep retries it after the one minute pause. | If it never posts, check GEMINI_API_KEY, then look for [meetings] voice recovery failed:. |
What was said is saved and the notes will be finished when the bot is back. | The meeting was ending as the bot shut down. | None. The next start finishes it. |
[voice] recovery: N finished, M failed | After a restart, interrupted voice meetings were finished or marked recovery_failed. | None. A failed one is not tried again. |
[voice] shutdown failed: <class> | Saving a running meeting at shutdown raised an error. | The transcript may not be saved. Check the log. |
See How voice notes work for how a meeting is processed.
Embeddings
Section titled “Embeddings”| Symptom | Likely cause | Fix |
|---|---|---|
[embeddings] disabled: GEMINI_API_KEY is not set or [ai] not configured (GEMINI_API_KEY unset) | No key. Summaries, asking, ticket prompts, meeting transcripts and voice notes need it too. | Set GEMINI_API_KEY. Ignore the line only if you use none of those. |
[embeddings] disabled | EMBEDDINGS_ENABLED is false. | Set it to true. While it is off, summaries still run but search messages by words only. |
[ai] retry attempt=N status=... delay=...ms | Gemini answered with an error that can be retried, and the bot is trying again. | Nothing to fix unless it repeats. Check the key and quota. |
[embeddings] sweep: ... remaining= is large | A big backlog. Each sweep embeds at most 2,000 messages, every EMBEDDING_SWEEP_HOURS hours. | Wait for later sweeps, or run bun run embeddings:backfill. |
[embeddings] queue full, dropped N; the sweep recovers them | A burst of new messages filled the embedding queue. | None. The next sweep embeds them. |
[embeddings] sweep failed: or [embeddings] batch failed: | A Gemini or database call failed during embedding. | Check GEMINI_API_KEY, quota and the database. The sweep tries again. |
embed-backfill: stopped, no progress | The key or quota is the problem. | Check GEMINI_API_KEY and your Gemini quota, then run it again. It resumes. |
Embeddings have no member-facing command. When they are off or behind, summaries still run but search by words only. Summaries stop completely only when GEMINI_API_KEY is missing.
- Configuration to check a value.
- Deploy to redeploy or roll back.