{"record":{"id":"c313d219a0b64d73","repo":"different-ai/openwork","slug":"connection-details-were-missing-from-the-worker-re","errorCode":null,"errorMessage":"Connection details were missing from the worker response.","messagePattern":"Connection details were missing from the worker response\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/background-agents-screen.tsx","lineNumber":328,"sourceCode":"    try {\n      const { response, payload } = await requestJson(\n        `/v1/workers/${encodeURIComponent(workerId)}/tokens`,\n        {\n          method: \"POST\",\n          body: JSON.stringify({ includeExpiringOpenworkUrl: true }),\n        },\n        12000,\n      );\n\n      if (!response.ok) {\n        throw new Error(\n          getErrorMessage(payload, `Failed to load connection details (${response.status}).`),\n        );\n      }\n\n      const tokens = getWorkerTokens(payload);\n      if (!tokens) {\n        throw new Error(\"Connection details were missing from the worker response.\");\n      }\n\n      const nextDetails: ConnectionDetails = {\n        openworkUrl: tokens.openworkUrl,\n        ownerToken: tokens.ownerToken,\n        clientToken: tokens.clientToken,\n        openworkAppConnectUrl: buildOpenworkAppConnectUrl(\n          runtimeConfig.openworkAppConnectUrl,\n          tokens.previewOpenworkUrl,\n          tokens.clientToken,\n          workerId,\n          workerName,\n          { autoConnect: true },\n        ),\n        openworkDeepLink: buildOpenworkDeepLink(\n          tokens.openworkUrl,\n          tokens.hostToken ?? tokens.ownerToken,\n          workerId,","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/background-agents-screen.tsx#L310-L346","documentation":"After a successful (2xx) connection-details response, loadConnectionDetails extracts worker tokens via getWorkerTokens(payload). If the payload does not contain the expected openworkUrl/ownerToken/clientToken structure, this error is thrown because the UI cannot connect to the worker without these credentials. It indicates a 2xx response missing required fields.","triggerScenarios":"The endpoint returns 200 but omits tokens (worker not fully provisioned), uses a different envelope, or omits the expiring OpenWork URL despite includeExpiringOpenworkUrl:true; proxies stripping fields.","commonSituations":"Sandbox mid-provisioning returns partial data; server version predates the expiring-URL feature; security hardening redacting owner/client tokens; client/server contract skew.","solutions":["Inspect the raw response body and compare with getWorkerTokens' expected fields (openworkUrl, ownerToken, clientToken).","Retry after provisioning completes — partial 200s are often transient.","Update getWorkerTokens if the server renamed/moved fields into an envelope.","Verify server and client versions are aligned; redeploy the stale side."],"exampleFix":"// before\nconst tokens = getWorkerTokens(payload);\nif (!tokens) throw new Error(\"Connection details were missing from the worker response.\");\n// after\nconst tokens = getWorkerTokens(payload?.worker ?? payload?.data ?? payload);\nif (!tokens) throw new Error(\"Connection details were missing from the worker response.\");","handlingStrategy":"type-guard","validationCode":"const tokens = getWorkerTokens(payload);\nif (!tokens || !tokens.openworkUrl || !tokens.ownerToken || !tokens.clientToken) {\n  // retry or show provisioning-in-progress state\n}","typeGuard":"function isWorkerTokens(v: unknown): v is { openworkUrl: string; ownerToken: string; clientToken: string } {\n  const t = v as Record<string, unknown> | null;\n  return !!t && typeof t.openworkUrl === \"string\" &&\n    typeof t.ownerToken === \"string\" && t.ownerToken.length > 0 &&\n    typeof t.clientToken === \"string\" && t.clientToken.length > 0;\n}","tryCatchPattern":"try {\n  await loadConnectionDetails();\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"missing from the worker response\")) {\n    showToast(\"Sandbox is still provisioning — retrying…\");\n    setTimeout(loadConnectionDetails, 5000);\n  } else throw err;\n}","preventionTips":["Treat a 200 without tokens as 'still provisioning' and retry with backoff instead of failing hard.","Contract-test the connection-details response including the expiring URL field.","Ensure security middleware never strips owner/client token fields.","Keep getWorkerTokens unwrapping aligned with the server response version."],"tags":["api-contract","response-parsing","background-agents"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}