{"record":{"id":"90c8d7ad132f5bf0","repo":"different-ai/openwork","slug":"token-not-found","errorCode":"token_not_found","errorMessage":"Token not found","messagePattern":"Token not found","errorType":"error_code","errorClass":"ApiError","httpStatus":404,"severity":"error","filePath":"apps/server/src/routes/core.ts","lineNumber":354,"sourceCode":"\n  addRoute(routes, \"POST\", \"/tokens\", \"host\", async (ctx) => {\n    ensureWritable(config);\n    const body = await readJsonBody(ctx.request);\n    const scopeRaw = typeof body.scope === \"string\" ? body.scope.trim() : \"\";\n    const scope = scopeRaw === \"owner\" || scopeRaw === \"collaborator\" || scopeRaw === \"viewer\" ? scopeRaw : null;\n    if (!scope) {\n      throw new ApiError(400, \"invalid_scope\", \"Token scope must be owner, collaborator, or viewer\");\n    }\n    const label = typeof body.label === \"string\" ? body.label.trim() : undefined;\n    const issued = await tokens.create(scope, { label });\n    return jsonResponse(issued, 201);\n  });\n\n  addRoute(routes, \"DELETE\", \"/tokens/:id\", \"host\", async (ctx) => {\n    ensureWritable(config);\n    const ok = await tokens.revoke(ctx.params.id);\n    if (!ok) {\n      throw new ApiError(404, \"token_not_found\", \"Token not found\");\n    }\n    return jsonResponse({ ok: true });\n  });\n\n  function rethrowEnvStoreReadError(error: unknown): never {\n    if (error instanceof EnvStoreReadError) {\n      throw new ApiError(\n        409,\n        error.code,\n        \"Environment variable store is invalid. Fix or remove the local env file before editing.\",\n      );\n    }\n    throw error;\n  }\n\n  // User-level env vars (see apps/app/pr/environment-variables.md). All routes\n  // require the desktop host token (not owner bearer tokens). List callers can\n  // request metadata-only results so renderer settings panes do not receive","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/routes/core.ts#L336-L372","documentation":"The DELETE /tokens/:id route deletes an API token by id via tokens.revoke(). The error is thrown when no token with the supplied id exists in the store, so revoke() returned false and the handler raises a 404 ApiError with code token_not_found. It is a normal client-side 404, not a server fault.","triggerScenarios":"Issuing DELETE /tokens/:id with an id that was never created, an id whose token was already revoked (delete is not idempotent — second call 404s), or an id from a different environment/store.","commonSituations":"A client retries a delete after a timeout when the first call actually succeeded; a UI holds a stale token list after another tab/agent revoked the token; tests hard-code token ids from fixtures.","solutions":["Fetch the current token list and confirm the id exists before deleting","Treat a 404 token_not_found on delete as success (already revoked) and continue","Check for stale cached token ids in the client; refresh the list after each revoke","Verify you are pointing at the same server/data directory that issued the token"],"exampleFix":"// before\nawait api.delete(`/tokens/${id}`); // throws 404 if already revoked\n// after\ntry { await api.delete(`/tokens/${id}`); }\ncatch (e) { if (e.code !== \"token_not_found\") throw e; }","handlingStrategy":"try-catch","validationCode":"const tokens = await api.get(\"/tokens\").then(r => r.json());\nconst exists = tokens.some(t => t.id === id);\nif (!exists) return; // nothing to revoke","typeGuard":"function isTokenNotFoundError(e: unknown): e is { code: \"token_not_found\"; status: 404 } {\n  return typeof e === \"object\" && e !== null && (e as { code?: string }).code === \"token_not_found\";\n}","tryCatchPattern":"try {\n  await api.delete(`/tokens/${id}`);\n} catch (e) {\n  if (isTokenNotFoundError(e)) return; // already revoked — treat as success\n  throw e;\n}","preventionTips":["Refresh the token list after every create/revoke so the UI never holds stale ids","Make delete flows idempotent on the client: swallow 404 token_not_found","Never hard-code token ids; always resolve them from the API","Include the server/environment in logs so cross-environment id mismatches are obvious"],"tags":["http-404","token-management","api"],"backgroundTag":"token-not-found","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}