{"record":{"id":"5543ab84252a6da1","repo":"can1357/oh-my-pi","slug":"devin-auth-error-getuserjwt-returned-an-empty-use","errorCode":null,"errorMessage":"Devin auth error: GetUserJwt returned an empty user JWT","messagePattern":"Devin auth error: GetUserJwt returned an empty user JWT","errorType":"exception","errorClass":"AIError.ProviderResponseError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/providers/devin.ts","lineNumber":512,"sourceCode":"\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"content-type\": \"application/proto\",\n\t\t\t\"connect-protocol-version\": \"1\",\n\t\t\taccept: \"*/*\",\n\t\t},\n\t\tbody: toBinary(GetUserJwtRequestSchema, request),\n\t\tsignal,\n\t});\n\tconst payload = new Uint8Array(await response.arrayBuffer());\n\tif (!response.ok) {\n\t\tthrow new AIError.DevinApiError(\n\t\t\t`Devin auth error ${response.status} ${response.statusText}: ${new TextDecoder().decode(payload)}`,\n\t\t\tresponse.status,\n\t\t);\n\t}\n\tconst decoded = decodeDevinUnaryMessage(GetUserJwtResponseSchema, payload);\n\tif (!decoded?.userJwt) {\n\t\tthrow new AIError.ProviderResponseError(\"Devin auth error: GetUserJwt returned an empty user JWT\", {\n\t\t\tprovider: \"devin\",\n\t\t\tkind: \"runtime\",\n\t\t});\n\t}\n\tconst customBaseUrl = decoded.customApiServerUrl.trim();\n\treturn { userJwt: decoded.userJwt, ...(customBaseUrl ? { baseUrl: customBaseUrl.replace(/\\/+$/, \"\") } : undefined) };\n}\n\n/**\n * Resolve a server-side router (`adaptive`) into the concrete model uid plus the\n * assignment JWT that authorizes it. The router uid is never a legal\n * `chatModelUid`, so a failed assignment must fail the turn rather than fall\n * back to sending the router id to `GetChatMessage`.\n */\nasync function assignDevinModel(\n\tmodel: Model<\"devin-agent\">,\n\tturn: DevinTurn,\n\tbaseUrl: string,","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/devin.ts#L494-L530","documentation":"Thrown by fetchDevinAuthMetadata when GetUserJwt returns HTTP 200 but the decoded GetUserJwtResponse carries no userJwt field. The server accepted the request but produced an unusable empty credential, so the library refuses to continue with a null JWT.","triggerScenarios":"Devin responds ok to GetUserJwt but the protobuf-decoded message lacks userJwt — e.g. a user account in a bad state, a server returning an empty/unpopulated response, or a server version whose response schema diverges from the bundled proto.","commonSituations":"Newly provisioned Devin account not yet fully initialized; Devin server version mismatch with the client's GetUserJwtRequest/Response schema; empty response from a misrouted gateway.","solutions":["Confirm the Devin account is fully provisioned and can issue user JWTs (log into the instance)","Re-run the request — transient empty responses occasionally clear on retry","Update pi-ai if your Devin server version changed the GetUserJwt response schema","Check the Devin instance logs for why it returned an empty JWT"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Ensure the account can mint JWTs before relying on it:\nconst res = await fetch(`${baseUrl}/user`, { headers: { authorization: `Bearer ${apiKey}` } });\nconst user = await res.json();\nif (!user || user.status !== \"active\") throw new Error(\"Devin account not active — cannot obtain user JWT\");","typeGuard":"function hasUserJwt(v: unknown): v is { userJwt: string } {\n  return typeof v === \"object\" && v !== null && typeof (v as { userJwt?: unknown }).userJwt === \"string\"\n    && (v as { userJwt: string }).userJwt.length > 0;\n}","tryCatchPattern":"try {\n  const meta = await fetchDevinAuthMetadata(baseUrl, request, signal);\n} catch (err) {\n  if (err instanceof AIError.ProviderResponseError && err.message.includes(\"empty user JWT\")) {\n    await Bun.sleep(1000); // transient empty responses often clear\n    return fetchDevinAuthMetadata(baseUrl, request, signal); // retry once\n  }\n  throw err;\n}","preventionTips":["Verify Devin account provisioning before automation runs","Keep client proto schema in sync with the Devin server version","Add a single retry with backoff for empty-response cases","Monitor Devin instance logs for repeated empty JWT responses"],"tags":["auth","devin","jwt","empty-response"],"backgroundTag":"jwt-token-expired","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}