Ludicord
Guide 23 · Reference

Troubleshooting

Diagnose Discord, OAuth2, routing, runtime, build, and deployment failures.

Ludicord 3.1.0Public source 20c4889

Start with the first error, not the last cascade. In development, the Ludicord panel shows browser and compile failures with source location; the terminal owns server, route, configuration, and build diagnostics.

#The error panel does not appear

The panel is development-only and requires a document response. If the browser shows raw JSON such as LUDICORD_DEV_ERROR, confirm you are running the latest Ludicord version and restart once after upgrading the framework package.

Terminalbash
1npm install ludicord@latest
2npm run dev

Then reproduce the error in an embed route. API requests intentionally return JSON and do not render an HTML overlay.

#The build was canceled

The build was canceled usually means the compiler was interrupted by a process shutdown, a second competing build, or a file watcher rebuilding while the command ended. It is not a successful package artifact.

  1. Stop duplicate ludicord dev or ludicord build processes.
  2. Run npx ludicord clean.
  3. Run npm run build once and wait for its final success or source error.
  4. If it fails again, fix the first diagnostic above the cancellation line.

Never publish or deploy after a canceled build.

#A route returns 404

Check the file convention first:

texttext
1app/embeds/home/embed.tsx
2app/api/hello/route.ts
3app/ws/audience/route.ts

Embed files must be named embed.tsx; API and WebSocket files must be named route.ts. Run npx ludicord routes to see what the compiler discovered. On case-sensitive production systems, Home and home are different directories.

#A new route is missing from TypeScript

Generated route types update after the route scanner completes. Save the file, watch for compiled app/..., and allow the editor to reload the TypeScript project. If the manifest remains stale:

Terminalbash
1npx ludicord clean
2npm run dev

Do not hand-edit .ludicord types; the next compile replaces them.

#Discord opens a blank or blocked Activity

Verify these values together:

CheckExpected
Activity URL mapping/ targets the current public tunnel hostname without https://
OAuth2 redirectMatches the URI documented for Discord's Activity proxy
Client IDSame application in Discord and LUDICORD_CLIENT_ID
Public originHTTPS and reachable from outside your computer
Development serverListening on the port your tunnel forwards

Open the public tunnel URL directly to separate tunnel failures from Discord configuration failures.

#Login loops or returns denied

Check LUDICORD_CLIENT_SECRET and LUDICORD_SESSION_SECRET in the server environment. Confirm the requested scopes are enabled for the same Discord application. Clear the Activity's cookies after changing application IDs or callback configuration.

Never prefix secrets with PUBLIC_. If a secret was exposed in client output, rotate it in the Discord Developer Portal before continuing.

#User, guild, or channel data is incomplete

Discord returns only data available to the current command, scope, channel type, and launch context. Inspect the resource status and diagnostics instead of replacing missing values with guessed data.

app/embeds/debug/embed.tsxtsx
1const discord = useDiscordData();
2const diagnostics = useDiscordDiagnostics();
3
4console.log(discord.channel?.typeName, discord.channel?.raw);
5console.log(diagnostics);

For server-fetched members, roles, and channels, check the hook's status, error, and pagination controls. Large guild member lists are paginated and can require Discord permissions.

#WebSockets connect but messages do not arrive

Check four boundaries:

  1. The client URL matches a generated app/ws/**/route.ts route.
  2. Both sides use the same named event.
  3. The server joins or broadcasts to the intended route, custom, or Activity-instance room.
  4. The proxy forwards WebSocket upgrades, not only HTTP requests.

Use connection status in the UI and add temporary server logs inside open, message, and close. A reconnect does not restore application state unless you request or synchronize it again.

#Shared state jumps backward

Do not maintain a second source of truth with an unrelated local useState. Update through useSharedActivityState and let revisions reject stale messages. Server validation should be deterministic and should not depend on browser-only state.

Shared state is Activity-instance scoped and stored in process memory by default. A process restart resets it; multi-instance deployments need a shared adapter before they can promise durable or cross-process synchronization.

#Production works locally but fails after deployment

Confirm the deployed Node version, environment variables, allowed host, HTTPS proxy headers, request body limit, and WebSocket upgrade support. Run the same commands locally that production runs:

Terminalbash
1npm ci
2npm run build
3npm run start

Test the health of the Activity page, one API route, authentication, and one WebSocket connection. A static-only host cannot run Ludicord's server routes, OAuth session exchange, or WebSocket runtime.

#Create a useful bug report

Include:

  • the first complete Ludicord diagnostic and source frame;
  • output from npx ludicord info with private values reviewed;
  • the smallest route or component that reproduces the failure;
  • Node and package-manager versions;
  • whether the issue occurs in the local browser, Discord, production, or all three.

Do not include Client Secrets, bot tokens, session secrets, raw access tokens, cookies, or private webhook URLs.

Return to Getting started to compare the failing project with the minimal working path.