{"record":{"id":"802eb2cc38bfcb29","repo":"different-ai/openwork","slug":"no-openwork-link-was-returned","errorCode":null,"errorMessage":"No OpenWork link was returned.","messagePattern":"No OpenWork link was returned\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/_components/workspace-claim-screen.tsx","lineNumber":216,"sourceCode":"  }, [claimBusy, claimedOrg, sessionHydrated, token, user]);\n\n  async function createDesktopHandoff(): Promise<string> {\n    const { response, payload } = await requestJson(\n      \"/v1/auth/desktop-handoff\",\n      {\n        method: \"POST\",\n        body: JSON.stringify({ desktopScheme: \"openwork\" }),\n      },\n      12000,\n    );\n\n    if (!response.ok) {\n      throw new Error(getErrorMessage(payload, `Could not prepare an OpenWork link (${response.status}).`));\n    }\n\n    const openworkUrl = getOpenworkUrl(payload);\n    if (!openworkUrl) {\n      throw new Error(\"No OpenWork link was returned.\");\n    }\n\n    return openworkUrl;\n  }\n\n  async function handleOpenDesktop() {\n    setHandoffBusy(true);\n    setHandoffError(null);\n    setHandoffAttempted(true);\n\n    try {\n      window.location.assign(await createDesktopHandoff());\n    } catch (error) {\n      setHandoffError(error instanceof Error ? error.message : \"Could not open OpenWork.\");\n    } finally {\n      setHandoffBusy(false);\n    }\n  }","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/_components/workspace-claim-screen.tsx#L198-L234","documentation":"workspace-claim-screen.tsx throws this when the desktop handoff request succeeds (2xx) but `getOpenworkUrl(payload)` cannot find an `openwork` URL in the response. The server acknowledged the handoff but did not return the link the client needs to continue.","triggerScenarios":"Handoff endpoint returns 2xx with a payload lacking the openwork URL field: `{}` , `{ url: null }`, or a differently-named field after an API change.","commonSituations":"Server/client API contract drift after a field rename; server bug where link generation silently fails but still returns 200; middleware stripping fields from the response; stale client bundle calling an updated server.","solutions":["Log the raw handoff response payload and compare against getOpenworkUrl's expected field","Align client and server on the same response schema (add a contract test)","Fix the server so it either returns the openwork URL or a proper error status","Hard-refresh / redeploy the web client so it is not running a stale bundle"],"exampleFix":"// before\nconst openworkUrl = getOpenworkUrl(payload);\nif (!openworkUrl) {\n  throw new Error(\"No OpenWork link was returned.\");\n}\n// after\nconst openworkUrl = getOpenworkUrl(payload) ?? (typeof payload?.link === \"string\" ? payload.link : null);\nif (!openworkUrl) {\n  throw new Error(\"No OpenWork link was returned.\");\n}","handlingStrategy":"type-guard","validationCode":"const payload = await res.json();\nconst url = (payload as { openworkUrl?: unknown }).openworkUrl;\nif (typeof url !== \"string\" || !url.startsWith(\"openwork://\")) {\n  console.warn(\"handoff response missing openwork URL\", payload);\n}","typeGuard":"function hasOpenworkUrl(p: unknown): p is { openworkUrl: string } {\n  return typeof p === \"object\" && p !== null && \"openworkUrl\" in p && typeof (p as { openworkUrl: unknown }).openworkUrl === \"string\" && (p as { openworkUrl: string }).openworkUrl.length > 0;\n}","tryCatchPattern":"try {\n  const url = getOpenworkUrl(payload);\n  if (!url) throw new Error(\"No OpenWork link was returned.\");\n} catch (err) {\n  showRetryableError(\"We could not generate your OpenWork link. Please try again or use sign-in code handoff instead.\");\n}","preventionTips":["Add a contract test for the handoff response schema shared by client and server","Have the server return 500 (not 200 with an empty payload) when link generation fails","Deploy client and server together when the handoff schema changes","Log the raw payload when getOpenworkUrl returns null"],"tags":["http","api-response","den-web","desktop-handoff"],"backgroundTag":"api-response-missing-field","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}