{"record":{"id":"f919ca7ef3504ca5","repo":"Budibase/budibase","slug":"token-is-required","errorCode":null,"errorMessage":"token is required","messagePattern":"token is required","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/api/controllers/ai/chatIdentityLinks.ts","lineNumber":112,"sourceCode":"        outline: 2px solid #2680eb;\n        outline-offset: 2px;\n      }\n      @media (max-width: 480px) {\n        body {\n          padding: 24px;\n        }\n        main {\n          min-height: 360px;\n        }\n        h1 {\n          font-size: 22px;\n        }\n      }\n`\n\nconst resolveToken = (token?: string) => {\n  if (!token) {\n    throw new HTTPError(\"token is required\", 400)\n  }\n  return token\n}\n\nconst assertSessionMatchesInstance = ({\n  workspaceId,\n  instance,\n}: {\n  workspaceId?: string\n  instance: string\n}) => {\n  if (!workspaceId || workspaceId !== instance) {\n    throw new HTTPError(\"Link token is not valid for this workspace\", 400)\n  }\n}\n\nconst getCurrentGlobalUserId = (ctx: UserCtx) => {\n  const currentUserId =","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/ai/chatIdentityLinks.ts#L94-L130","documentation":"resolveToken is a small helper that guarantees a link token exists before any chat identity link flow proceeds. Identity linking works by handing a one-time token from a chat channel to the web app via URL; without a token there is nothing to resolve. The throw is an HTTP 400 guarding routes like /api/chat-links/:instance/:token/... .","triggerScenarios":"Hitting a chat-links route (handoff or confirm) with an empty or missing :token path parameter, or calling resolveToken with undefined because the URL was constructed without the token segment.","commonSituations":"Manually typing/truncating the confirmation URL from an email/chat message; a chat bot rendering the link without the token placeholder substituted; links copied without the final path segment; redirect logic losing the token query/path param.","solutions":["Use the exact handoff/confirmation URL supplied by the chat channel message, including the token segment","Regenerate the link token by re-issuing the link request from the chat (e.g. typing the link command again)","Fix link-rendering code so the token is interpolated into the URL template","Check route definitions so the :token param is actually captured by the router"],"exampleFix":"// before\nconst res = await fetch(`/api/chat-links/${instance}/handoff`)\n// after\nconst res = await fetch(`/api/chat-links/${instance}/${token}/handoff`)","handlingStrategy":"validation","validationCode":"if (!token) throw new Error(\"chat link token missing from URL\")\nawait fetch(`/api/chat-links/${instance}/${token}/handoff`)","typeGuard":"function hasToken(params: { token?: string }): params is { token: string } {\n  return typeof params.token === \"string\" && params.token.length > 0\n}","tryCatchPattern":"try {\n  await api.handoffLink(instance, token)\n} catch (e) {\n  if (e instanceof HTTPError && e.status === 400 && e.message === \"token is required\") {\n    // fix link construction / prompt user to use the full link\n  }\n  throw e\n}","preventionTips":["Generate link URLs from a single template that interpolates the token","Never truncate or manually retype link tokens","Validate that the router captures the :token param","E2E-test the full handoff URL produced by the chat message"],"tags":["validation","http-400","identity-link"],"backgroundTag":"missing-required-field","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}