can1357/oh-my-pi · error · AIError.ProviderResponseError

Devin AssignModel error: response carried no assignment JWT

Error message

Devin AssignModel error: response carried no assignment JWT and model uid

What it means

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).

Source

Thrown at packages/ai/src/providers/devin.ts:559

		method: "POST",
		headers: {
			"content-type": "application/proto",
			"connect-protocol-version": "1",
			accept: "*/*",
		},
		body: toBinary(AssignModelRequestSchema, request),
		signal,
	});
	const payload = new Uint8Array(await response.arrayBuffer());
	if (!response.ok) {
		throw new AIError.DevinApiError(
			`Devin AssignModel error ${response.status} ${response.statusText}: ${new TextDecoder().decode(payload)}`,
			response.status,
		);
	}
	const assignment = decodeDevinUnaryMessage(AssignModelResponseSchema, payload)?.assignment;
	if (!assignment?.assignmentJwt || !assignment.modelUid) {
		throw new AIError.ProviderResponseError(
			"Devin AssignModel error: response carried no assignment JWT and model uid",
			{ provider: model.provider, kind: "runtime" },
		);
	}
	logger.debug("devin: router assigned a model", {
		router: model.requestModelId ?? model.id,
		assigned: assignment.modelUid,
	});
	return assignment;
}

/**
 * The prompt the router scores: the current user/developer turn on its own.
 * Native leaves `messageId` empty here — the id for the turn is minted by the
 * chat request that follows.
 */
function buildRouterPrompt(messages: Message[]): ChatMessagePrompt | undefined {
	for (let index = messages.length - 1; index >= 0; index--) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry the request — transient empty assignments often succeed on a second attempt
  2. Confirm the account has entitlements for the requested model on the Devin instance
  3. Update pi-ai if the Devin server's AssignModelResponse schema has changed
  4. Inspect Devin instance logs to see why the assignment came back incomplete
Defensive patterns

Strategy: retry

Validate before calling

// Verify entitlement before assigning:
const entitled = await fetch(`${devinBaseUrl}/entitlements`, { headers: { authorization: `Bearer ${jwt}` } }).then(r => r.json());
if (!entitled.models?.includes(modelUid)) throw new Error(`Account lacks entitlement for ${modelUid}`);

Type guard

function hasAssignment(v: unknown): v is { assignmentJwt: string; modelUid: string } {
  if (typeof v !== "object" || v === null) return false;
  const a = v as { assignmentJwt?: unknown; modelUid?: unknown };
  return typeof a.assignmentJwt === "string" && a.assignmentJwt.length > 0 && typeof a.modelUid === "string" && a.modelUid.length > 0;
}

Try / catch

try {
  const assignment = await assignDevinModel(model, request, signal);
} catch (err) {
  if (err instanceof AIError.ProviderResponseError && err.message.includes("no assignment JWT")) {
    await Bun.sleep(500);
    return assignDevinModel(model, request, signal); // retry once for transient empty assignments
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/7613ec966b01371b. Report an issue: GitHub.