{"record":{"id":"0750d5021f42e6bd","repo":"JuliusBrussee/caveman","slug":"device-login-failed-server-did-not-provide-a-deli","errorCode":null,"errorMessage":"device login failed: server did not provide a delivery acknowledgement token","messagePattern":"device login failed: server did not provide a delivery acknowledgement token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":9761,"sourceCode":"\t    ...(typeof tok.gateway_key_id === \"string\" && tok.gateway_key_id ? { gateway_key_id: tok.gateway_key_id } : {}),\n\t    ...(typeof tok.project_id === \"string\" && tok.project_id ? { project_id: tok.project_id } : {}),\n\t  };\n\t  const tokenStore = storeCredentials(credentials);\n\t  const organizationId = orgFromToken(accessToken);\n\t  const gateway = instance ? \"\" : resolveLoginGatewayUrl(baseURL, tok, code, argv);\n\t  const saved: Config = { baseURL, token: \"\", tokenStore };\n\t  if (organizationId) saved.organizationId = organizationId;\n\t  if (credentials.project_id) saved.projectId = credentials.project_id;\n\t  if (gateway) saved.gatewayUrl = gateway;\n\t  // Persist the complete local login state before the server-side receipt fence:\n\t  // an ACK may permanently purge the replay bundle, so a config write that fails\n\t  // must leave the grant retryable rather than acknowledging an undiscoverable\n\t  // credential.\n\t  await saveConfig(saved);\n\t  const durableGrant = Boolean(credentials.refresh_token || credentials.gateway_api_key || credentials.gateway_key_id || credentials.project_id);\n\t  const ackToken = typeof tok.delivery_ack_token === \"string\" ? tok.delivery_ack_token : \"\";\n\t  if (durableGrant) {\n\t    if (!ackToken) throw new Error(\"device login failed: server did not provide a delivery acknowledgement token\");\n\t    // Do not print authenticated success or continue the post-login bridge\n\t    // until the control plane has recorded that this CLI stored the bundle.\n\t    await acknowledgeDeviceGrant(baseURL, credentials.access_token, code.device_code, ackToken);\n\t  }\n      if (instance) {\n        print({ authenticated: true, baseURL, organization_id: organizationId ?? null, project_id: credentials.project_id, scope: tok.scope, credential_kind: \"none\", token_store: tokenStore });\n        return;\n      }\n      // Mint/refresh the local-wrap entitlement for this device. Best\n      // effort: login never fails for seats or a down entitlement service.\n      await fetchAndStoreWrapEntitlement(baseURL, credentials.access_token);\n      if (gateway && wrapMode(gateway) === \"managed\") {\n        console.error(`  ${mark(\"ok\")} wrap now routes through the managed gateway (${gateway}) — governed reporting; verified stays zero without qualifying provider evidence`);\n      } else if (gateway) {\n        console.error(`  ${mark(\"ok\")} connected; wrap routes through ${gateway}`);\n      }\n      console.error(SYNC_DISCLOSURE);\n      print({ authenticated: true, baseURL, gateway_url: gateway || null, organization_id: organizationId ?? null, token_store: tokenStore });","sourceCodeStart":9743,"sourceCodeEnd":9779,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L9743-L9779","documentation":"If the token response produced a durable grant (refresh token, gateway key material, or project_id) but no delivery_ack_token, the CLI throws before acknowledging. The acknowledgement proves to the control plane that the CLI stored the credential; acknowledging an undiscoverable credential would be unsafe, so the flow stops. Note the credentials are already saved locally before this check.","triggerScenarios":"The token payload includes at least one of refresh_token, gateway_api_key, gateway_key_id, or project_id, but delivery_ack_token is missing, non-string, or empty.","commonSituations":"Authorization server version older than the CLI, not yet emitting delivery_ack_token; partial token response after a server-side error; misconfigured grant template on a private instance.","solutions":["Upgrade the private instance's authorization server to a version that issues delivery_ack_token for durable grants","Re-run login to get a complete token bundle","If the grant should be ephemeral, reconfigure the server to stop issuing refresh tokens/gateway keys for this client","Check instance logs for why the token response was incomplete"],"exampleFix":"// before\n{ \"refresh_token\": \"...\", \"project_id\": \"...\" } // no delivery_ack_token\n// after\n{ \"refresh_token\": \"...\", \"project_id\": \"...\", \"delivery_ack_token\": \"...\" }","handlingStrategy":"validation","validationCode":"const durable = !!(tok.refresh_token || tok.gateway_api_key || tok.gateway_key_id || tok.project_id);\nif (durable && (typeof tok.delivery_ack_token !== \"string\" || !tok.delivery_ack_token)) throw new Error(\"durable grant missing delivery_ack_token\");","typeGuard":"function hasAckToken(tok) { return typeof tok?.delivery_ack_token === \"string\" && tok.delivery_ack_token.length > 0; }","tryCatchPattern":"try { await login({ instance }) } catch (e) { if (e.message.includes(\"delivery acknowledgement token\")) console.error(\"Server did not issue delivery_ack_token; upgrade the instance or re-login\"); }","preventionTips":["Keep the instance's authorization server at a version that emits delivery_ack_token","Re-login rather than reusing partial token bundles","Alert on token responses lacking delivery_ack_token for durable grants"],"tags":["oauth","device-flow","unexpected-response","validation"],"backgroundTag":"empty-required-field","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}