hcengineering/platform · error · PlatformError
platform.status.BadRequest
platform.status.BadRequest
Error message
BadRequest
What it means
After resolving the account, createAccessLink requires the decoded token to carry a workspace UUID. When decodeTokenVerbose returns workspace == null (token has no workspace claim), the platform throws BadRequest. It signals a malformed token rather than missing data.
Source
Thrown at server/account/src/operations.ts:770
extra?: string
navigateUrl?: string
spaces?: string[]
notBefore?: number
expiration?: number
personalized?: boolean
}
): Promise<string> {
const { role, firstName, lastName, navigateUrl, spaces, notBefore, expiration, personalized = true } = params
const { account, workspace: workspaceUuid, extra } = decodeTokenVerbose(ctx, token)
const currentAccount = await db.account.findOne({ uuid: account })
if (currentAccount == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, { account }))
}
if (workspaceUuid == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {}))
}
const workspace = await db.workspace.findOne({ uuid: workspaceUuid })
if (workspace == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.WorkspaceNotFound, { workspaceUuid }))
}
let extraObj: Record<string, string> | undefined
if (params.extra != null) {
try {
extraObj = JSON.parse(params.extra)
} catch (e) {
ctx.error("Invalid extra parameter, couldn't parse JSON", { extra: params.extra })
throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {}))
}
}
View on GitHub (pinned to 63e28dc964)
Solutions
- Mint the token in a workspace context (after the user selects/joins a workspace) before calling createAccessLink.
- Decode the token locally and check the workspace claim is present before the call.
- Upgrade/align client and server versions so token minting includes the workspace claim.
Example fix
// before: token without workspace claim
const link = await createAccessLink(noWorkspaceToken, params)
// after: ensure token carries workspace
const payload = decodeJwt(noWorkspaceToken)
if (payload.workspace == null) throw new Error('token has no workspace; re-authenticate')
const link = await createAccessLink(noWorkspaceToken, params) Defensive patterns
Strategy: validation
Validate before calling
const payload = decodeJwt(token)
if (payload?.workspace == null) {
throw new Error('Token has no workspace claim; authenticate within a workspace context first')
} Type guard
function hasWorkspaceClaim(t: unknown): t is { account: string; workspace: string } {
return typeof t === 'object' && t !== null &&
typeof (t as any).workspace === 'string' && (t as any).workspace.length > 0
} Prevention
- Only mint tokens after the user has selected/joined a workspace.
- Decode and sanity-check token claims before each API call.
- Keep token-issuing and token-consuming service versions aligned.
When it happens
Trigger: Calling createAccessLink with a token that lacks a workspace claim — e.g. a token minted without a selected workspace, a system/anonymous token, or a truncated token payload.
Common situations: Using pre-workspace-selection tokens (right after signup before joining a workspace); tokens issued by older service versions without the workspace field; hand-built test tokens omitting claims.
Related errors
- Invalid workspace login info by token
- platform.status.WorkspaceNotFound
- Couldn't find workspace with the provided token
- platform.status.Unauthorized
- Workspace or account not found in token
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/c5cb90bbf036b211.
Report an issue: GitHub.