{"record":{"id":"7613ec966b01371b","repo":"can1357/oh-my-pi","slug":"devin-assignmodel-error-response-carried-no-assig","errorCode":null,"errorMessage":"Devin AssignModel error: response carried no assignment JWT and model uid","messagePattern":"Devin AssignModel error: response carried no assignment JWT and model uid","errorType":"exception","errorClass":"AIError.ProviderResponseError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/providers/devin.ts","lineNumber":559,"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(AssignModelRequestSchema, 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 AssignModel error ${response.status} ${response.statusText}: ${new TextDecoder().decode(payload)}`,\n\t\t\tresponse.status,\n\t\t);\n\t}\n\tconst assignment = decodeDevinUnaryMessage(AssignModelResponseSchema, payload)?.assignment;\n\tif (!assignment?.assignmentJwt || !assignment.modelUid) {\n\t\tthrow new AIError.ProviderResponseError(\n\t\t\t\"Devin AssignModel error: response carried no assignment JWT and model uid\",\n\t\t\t{ provider: model.provider, kind: \"runtime\" },\n\t\t);\n\t}\n\tlogger.debug(\"devin: router assigned a model\", {\n\t\trouter: model.requestModelId ?? model.id,\n\t\tassigned: assignment.modelUid,\n\t});\n\treturn assignment;\n}\n\n/**\n * The prompt the router scores: the current user/developer turn on its own.\n * Native leaves `messageId` empty here — the id for the turn is minted by the\n * chat request that follows.\n */\nfunction buildRouterPrompt(messages: Message[]): ChatMessagePrompt | undefined {\n\tfor (let index = messages.length - 1; index >= 0; index--) {","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/devin.ts#L541-L577","documentation":"Thrown by assignDevinModel when AssignModel returns HTTP 200 but the decoded AssignModelResponse is missing either assignmentJwt or modelUid. Without both, the library cannot authenticate the subsequent stream against the assigned model, so it fails fast with a ProviderResponseError (kind: runtime).","triggerScenarios":"Devin accepts the assignment request but the response's assignment field is absent or partially populated — server-side assignment race, account without model entitlements, or proto schema drift between client and server.","commonSituations":"Devin router returned an empty/partial assignment during a load or outage; user account lacking entitlement to the requested model; Devin server version mismatch with the bundled protobuf definitions.","solutions":["Retry the request — transient empty assignments often succeed on a second attempt","Confirm the account has entitlements for the requested model on the Devin instance","Update pi-ai if the Devin server's AssignModelResponse schema has changed","Inspect Devin instance logs to see why the assignment came back incomplete"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Verify entitlement before assigning:\nconst entitled = await fetch(`${devinBaseUrl}/entitlements`, { headers: { authorization: `Bearer ${jwt}` } }).then(r => r.json());\nif (!entitled.models?.includes(modelUid)) throw new Error(`Account lacks entitlement for ${modelUid}`);","typeGuard":"function hasAssignment(v: unknown): v is { assignmentJwt: string; modelUid: string } {\n  if (typeof v !== \"object\" || v === null) return false;\n  const a = v as { assignmentJwt?: unknown; modelUid?: unknown };\n  return typeof a.assignmentJwt === \"string\" && a.assignmentJwt.length > 0 && typeof a.modelUid === \"string\" && a.modelUid.length > 0;\n}","tryCatchPattern":"try {\n  const assignment = await assignDevinModel(model, request, signal);\n} catch (err) {\n  if (err instanceof AIError.ProviderResponseError && err.message.includes(\"no assignment JWT\")) {\n    await Bun.sleep(500);\n    return assignDevinModel(model, request, signal); // retry once for transient empty assignments\n  }\n  throw err;\n}","preventionTips":["Confirm model entitlements on the Devin account before automation","Retry once on empty assignment responses — often a server-side race","Keep the client's AssignModel proto in sync with your Devin server version","Alert on repeated partial AssignModel responses; they signal service degradation"],"tags":["devin","model-assignment","empty-response","jwt"],"backgroundTag":"empty-response-body","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}