Budibase/budibase · error · HTTPError
Link token is not valid for this workspace
Error message
Link token is not valid for this workspace
What it means
assertSessionMatchesInstance ensures the workspace (instance) encoded in the stored link-token session matches the :instance path parameter of the request. This prevents a token issued for one workspace/app from being redeemed against another. If workspaceId is missing or differs from the instance in the URL, a 400 is thrown.
Source
Thrown at packages/server/src/api/controllers/ai/chatIdentityLinks.ts:125
}
`
const resolveToken = (token?: string) => {
if (!token) {
throw new HTTPError("token is required", 400)
}
return token
}
const assertSessionMatchesInstance = ({
workspaceId,
instance,
}: {
workspaceId?: string
instance: string
}) => {
if (!workspaceId || workspaceId !== instance) {
throw new HTTPError("Link token is not valid for this workspace", 400)
}
}
const getCurrentGlobalUserId = (ctx: UserCtx) => {
const currentUserId =
ctx.user?.globalId ||
getGlobalIDFromUserMetadataID(ctx.user?._id || "") ||
ctx.user?._id
if (!currentUserId) {
throw new HTTPError("Unable to resolve current user", 400)
}
return currentUserId
}
const providerDisplayName = (provider: ChatIdentityLinkProvider) => {
if (provider === AgentChannelProvider.MSTEAMS) {
return "Teams"
}View on GitHub (pinned to a81a902e9a)
Solutions
- Open the link exactly as generated, matching the workspace it was issued for
- Regenerate the identity link from within the correct workspace
- If the app was recreated/migrated, re-issue the link so session.workspaceId matches the new instance id
- Fix link-generation code to embed the current workspace id in the instance path segment
Example fix
// before
// token issued in workspaceId=app_dev, but requesting:
fetch(`/api/chat-links/${otherInstanceId}/${token}/confirm`)
// after
fetch(`/api/chat-links/${workspaceId}/${token}/confirm`) Defensive patterns
Strategy: validation
Validate before calling
if (session.workspaceId !== instanceId) throw new Error("link token belongs to a different workspace") Type guard
function matchesInstance(session: { workspaceId?: string }, instance: string): session is { workspaceId: string } {
return typeof session.workspaceId === "string" && session.workspaceId === instance
} Try / catch
try {
await api.confirmLink(instance, token)
} catch (e) {
if (e instanceof HTTPError && e.status === 400 && e.message.includes("not valid for this workspace")) {
// re-issue the link from the correct workspace
}
throw e
} Prevention
- Only open chat link URLs from the workspace that issued them
- Regenerate links after app migration/recreation
- Include the workspace id in link generation from one source of truth
- For multi-app users, disambiguate which app a link belongs to before clicking
When it happens
Trigger: Redeeming a handoff or confirm link where the instance segment in the URL does not equal session.workspaceId — e.g. swapping the workspace id in the URL, using a token generated in app A while browsing app B, or a session stored without a workspaceId.
Common situations: Multi-tenant environments where users belong to several apps and paste a link into the wrong app's domain/URL; environments migrated or renamed instances so stored workspaceId no longer matches; copying an old link after the app was recreated with a new id.
Related errors
- token is required
- Error getting status
- Unable to remove doc without a valid _id and _rev.
- Cannot store document without _id field.
- Configuration invalid. Must contain google clientID and clie
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/195e76f8da2def3f.
Report an issue: GitHub.