{"record":{"id":"33582933bdbf520b","repo":"different-ai/openwork","slug":"failed-to-rotate-scim-token-response-status","errorCode":null,"errorMessage":"Failed to rotate SCIM token (${response.status}).","messagePattern":"Failed to rotate SCIM token \\((.+?)\\)\\.","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/scim-screen.tsx","lineNumber":175,"sourceCode":"    if (!orgId) {\n      setError(\"Organization not found.\");\n      return;\n    }\n\n    setError(null);\n    setVisibleToken(null);\n    try {\n      await runReauthableAction(\"rotate-scim-token\", async () => {\n        setRotating(true);\n        try {\n          const { response, payload } = await requestJson(\n            \"/v1/scim/token\",\n            { method: \"POST\", body: JSON.stringify({}) },\n            12000,\n          );\n\n          if (!response.ok) {\n            throw getRequestError(payload, response, `Failed to rotate SCIM token (${response.status}).`);\n          }\n\n          const parsed = parseOrgScimPayload(payload);\n          if (!parsed.baseUrl || !parsed.connection || !parsed.scimToken) {\n            throw new Error(\"SCIM token rotation succeeded, but the response was incomplete.\");\n          }\n\n          setBaseUrl(parsed.baseUrl);\n          setSsoReady(parsed.ssoReady);\n          setConnection(parsed.connection);\n          setHealth(parsed.health);\n          setVisibleToken(parsed.scimToken);\n          setCopiedValue(null);\n        } finally {\n          setRotating(false);\n        }\n      });\n    } catch (nextError) {","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/scim-screen.tsx#L157-L193","documentation":"handleRotateToken in scim-screen.tsx throws this when POST /v1/scim/token with an empty body returns non-ok. Token rotation is a privileged, single-shot operation; the error means the Den API refused it. Note a follow-up error ('rotation succeeded, but the response was incomplete') exists for a 2xx with a bad payload — this one is strictly the non-ok branch.","triggerScenarios":"POST /v1/scim/token returns 401 (session expired), 403 (caller is not an org admin), 404 (no SCIM connection exists to rotate a token for), 409/412 (concurrent rotation), or 5xx.","commonSituations":"Admin clicks 'Rotate token' while their session just expired; rotating before any SCIM connection has been established; two admins rotating simultaneously; server hiccup during the write.","solutions":["Ensure a SCIM connection exists first — rotation without a connection returns 404.","For 401, re-authenticate; for 403, switch to an org-admin account.","Retry once after transient 5xx; if 409, coordinate with other admins and rotate once.","After success, immediately copy the new token — it is only shown once."],"exampleFix":"// before\nawait rotateToken();\n// after: require an existing connection first\nif (!connection) {\n  throw new Error('Provision the SCIM connection before rotating its token.');\n}\nawait rotateToken();","handlingStrategy":"try-catch","validationCode":"if (!connection) {\n  throw new Error('Create the SCIM connection before rotating its token.');\n}\nconst session = await auth.getSession();\nif (!session) redirectToSignIn();","typeGuard":"function hasConnection(v: unknown): v is { connection: Record<string, unknown> } {\n  return typeof v === 'object' && v !== null &&\n    typeof (v as Record<string, unknown>).connection === 'object' &&\n    (v as Record<string, unknown>).connection !== null;\n}","tryCatchPattern":"try {\n  await rotateToken();\n  toast('New SCIM token generated — copy it now; it will not be shown again.');\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (msg.includes('404')) toast('No SCIM connection exists yet.');\n  else if (msg.includes('403')) toast('Only org admins can rotate the SCIM token.');\n  else toast(msg);\n}","preventionTips":["Only expose the rotate action when a connection exists.","Confirm with a dialog — rotation invalidates the old token for the IdP immediately.","Coordinate token rotation with IdP config updates to avoid provisioning outages.","Re-authenticate long-idle admin tabs before privileged actions."],"tags":["http","api","scim","token-rotation"],"backgroundTag":"http-non-ok-response","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}