Skip to content

Troubleshooting

My app doesn’t show up in the dev console

Section titled “My app doesn’t show up in the dev console”
  1. Check linkworld login succeeded — ~/.config/linkworld/config.json should have a token field.
  2. Hit https://linkworld.ai/api/dev/me with the token — should return your dev account.
  3. If you used linkworld init, you also need linkworld deploy at least once before the app appears under “Your apps”.

linkworld deploy says “manifest validation failed”

Section titled “linkworld deploy says “manifest validation failed””

The CLI runs the same Pydantic schema as the platform. Read the error carefully — it points at the field. Common causes:

  • Tool name not lowercase: BadName should be bad_name
  • Top-level field misspelled: runtimeImage: instead of runtime: { image: ... }
  • apiVersion not exactly linkworld.ai/v2
  • runtime.port outside 1024–65535

ctx.tools.call(...) raises ToolCallError(scope_denied)

Section titled “ctx.tools.call(...) raises ToolCallError(scope_denied)”

The tenant didn’t grant the scope your tool call needs. Fixes:

  1. Confirm the scope is in your manifest.required_scopes.
  2. The tenant admin must re-install (or re-grant) on their side.
  3. Catch and degrade gracefully — see Best practices.

Walk the lookup chain:

  1. Did you linkworld secrets set KEY=... for the dev-default? Check linkworld secrets list --app <slug>.
  2. The key must match ^[A-Z][A-Z0-9_]{0,63}$. Lowercase or spaces fail silently — the SDK validates client-side.
  3. Network error reaching the platform also returns null (fail-closed). Check container logs for the underlying error.

For lifecycle hooks: check manifest.lifecycle.<hook>: true. The SDK refuses to register a handler whose flag is false at construction time — if app.run() started without complaint, the wiring is correct.

For on_inbound: the tenant has to opt into fan-out for your app in their app-settings UI. Without that opt-in, the platform routes the inbound to its standard agent and your app never sees it.

For schedules: the platform’s leader-elected scanner ticks every 60s. If your cron is * * * * *, expect ±60s jitter. If you see no ticks at all, check your cron syntax — 0 8 * * 1-5 runs Mon-Fri at 08:00, not every 8 hours.

Check the container logs in the dev console (Logs tab) or in your local docker logs if running via linkworld deploy --skip-build on a self-hosted VM:

  • platform credentials missing: the platform didn’t inject LINKWORLD_MCP_URL / LINKWORLD_MCP_TOKEN. Probably a platform-side bug — file an issue.
  • Health check fails: your runtime.port doesn’t match the port your handler binds to. Fix the manifest.
  • Image pull fails: the GHCR image isn’t public. Either make it public or coordinate with the platform admin to add pull credentials.

”OAuth completed but token was rejected”

Section titled “”OAuth completed but token was rejected””

The OAuth flow worked but the JWT validation in /api/dev/me failed. Most likely:

  • The dev-account row was suspended after the JWT was minted.
  • Wall-clock skew between the platform and the JWT issuer (rare; both are NTP-synced).
  • The platform’s supabase_jwt_secret rotated (very rare; coordinate with admin).

Sign out, sign in again. If the new token also fails, contact platform support.

  • LINKWORLD_LOCAL=1 is required (or app.run({ local: true })). Without it the SDK tries to find platform credentials and refuses to start.
  • The mock tools have to be registered before they’re called. If a handler calls email_send and you haven’t POST /__mock/tool for it yet, you get ToolCallError(decision='not_found').
  • The /__mock/secret endpoint sets in-process state; restart the app and you start fresh.
  • Audit rows are written per tool call. If your handler doesn’t call any platform tools, it doesn’t produce audit rows.
  • The Logs tab polls every 10s. Newly-arrived rows take up to that long to appear.
  • In local mode, audit rows go to stdout, not the platform — they don’t show up in any dev console.

The platform’s image registration call to GHCR can be slow on first publish (it pulls the image to verify it’s reachable). Default timeout is 60s. Workarounds:

Terminal window
# Pre-pull the image yourself first
docker pull ghcr.io/you/my-app:0.1.0
linkworld deploy --skip-build --version 0.1.0

If it still times out, check that the image is public on GHCR or that the platform’s pull token has access.