{"record":{"id":"27671551e9d795e0","repo":"hcengineering/platform","slug":"documentname-must-include-workspace-id","errorCode":null,"errorMessage":"documentName must include workspace id","messagePattern":"documentName must include workspace id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/collaborator/src/extensions/authentication.ts","lineNumber":63,"sourceCode":"        const readonly = isReadOnlyOrGuest(token.account, token.extra)\n\n        ctx.info('authenticate', {\n          workspaceId,\n          account: token.account,\n          mode: token.extra?.mode ?? '',\n          readonly\n        })\n\n        if (readonly) {\n          data.connection.readOnly = true\n        }\n\n        // verify workspace can be accessed with the token\n        const ids = await getWorkspaceIds(data.token)\n\n        // verify workspace uuid in the document matches the token\n        if (ids.uuid !== workspaceId) {\n          throw new Error('documentName must include workspace id')\n        }\n\n        return buildContext(data, ids)\n      },\n      { workspaceId }\n    )\n  }\n}\n","sourceCodeStart":45,"sourceCodeEnd":72,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/server/collaborator/src/extensions/authentication.ts#L45-L72","documentation":"During Hocuspocus authentication, onAuthenticate extracts the workspace id from the document name, fetches the workspace ids allowed for the token via getWorkspaceIds(data.token), and compares them. If ids.uuid !== workspaceId it throws this error, meaning the token is not authorized for the workspace encoded in the document name (or the document name is malformed).","triggerScenarios":"Connecting a collaboration client with a documentName whose embedded workspace uuid does not match the token's workspace; using a token issued for workspace A on a document of workspace B; or passing a documentName without the expected '<workspaceId>...' format.","commonSituations":"Hardcoded or cached document names from another environment, stale tokens after a workspace migration, multi-tenant frontends mixing workspace ids, or tests reusing a document name from a different account.","solutions":["Verify the document name embeds the same workspace uuid the token was issued for.","Re-acquire the token for the correct workspace (token may be from another tenant or expired-and-reissued for a different uuid).","Check getWorkspaceIds/token issuer config to ensure the right workspace is associated with the account.","If workspace ids changed (migration/rename), regenerate document names and tokens from the current workspace record."],"exampleFix":"// before\nconst docName = `${oldWorkspaceId}:${docId}` // stale id\nprovider = new HocuspocusProvider({ name: docName, token })\n\n// after\nconst docName = `${currentWorkspace.uuid}:${docId}`\nif (!docName.startsWith(currentWorkspace.uuid)) {\n  throw new Error('document name workspace id mismatch with token')\n}\nprovider = new HocuspocusProvider({ name: docName, token })","handlingStrategy":"validation","validationCode":"function documentNameFor (workspaceUuid: string, docId: string): string {\n  const name = `${workspaceUuid}:${docId}`\n  if (!name.startsWith(workspaceUuid)) throw new Error('documentName must include workspace id')\n  return name\n}\n// client: ensure token and workspaceUuid come from the same auth response","typeGuard":"function hasMatchingWorkspace (docName: string, tokenWorkspaceUuid: string): boolean {\n  return typeof docName === 'string' && docName.startsWith(`${tokenWorkspaceUuid}:`)\n}","tryCatchPattern":"try {\n  await connectProvider(documentName, token)\n} catch (err) {\n  if (err.message.includes('documentName must include workspace id')) {\n    console.error('Token/workspace mismatch: re-authenticate for workspace', documentName.split(':')[0])\n    await refreshTokenForWorkspace(workspaceId)\n  } else {\n    throw err\n  }\n}","preventionTips":["Always derive documentName's workspace prefix from the same auth payload that issued the token.","Never hardcode or cache workspace ids across environments or tenants.","After workspace migration/rename, reissue both tokens and document names together.","Validate document name format client-side before opening a provider connection."],"tags":["authentication","authorization","websocket","workspace"],"backgroundTag":"workspace-token-mismatch","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}