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

Devin auth error: GetUserJwt returned an empty user JWT

Error message

Devin auth error: GetUserJwt returned an empty user JWT

What it means

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.

Source

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

		method: "POST",
		headers: {
			"content-type": "application/proto",
			"connect-protocol-version": "1",
			accept: "*/*",
		},
		body: toBinary(GetUserJwtRequestSchema, request),
		signal,
	});
	const payload = new Uint8Array(await response.arrayBuffer());
	if (!response.ok) {
		throw new AIError.DevinApiError(
			`Devin auth error ${response.status} ${response.statusText}: ${new TextDecoder().decode(payload)}`,
			response.status,
		);
	}
	const decoded = decodeDevinUnaryMessage(GetUserJwtResponseSchema, payload);
	if (!decoded?.userJwt) {
		throw new AIError.ProviderResponseError("Devin auth error: GetUserJwt returned an empty user JWT", {
			provider: "devin",
			kind: "runtime",
		});
	}
	const customBaseUrl = decoded.customApiServerUrl.trim();
	return { userJwt: decoded.userJwt, ...(customBaseUrl ? { baseUrl: customBaseUrl.replace(/\/+$/, "") } : undefined) };
}

/**
 * Resolve a server-side router (`adaptive`) into the concrete model uid plus the
 * assignment JWT that authorizes it. The router uid is never a legal
 * `chatModelUid`, so a failed assignment must fail the turn rather than fall
 * back to sending the router id to `GetChatMessage`.
 */
async function assignDevinModel(
	model: Model<"devin-agent">,
	turn: DevinTurn,
	baseUrl: string,

View on GitHub (pinned to 9690622007)

Solutions

  1. Confirm the Devin account is fully provisioned and can issue user JWTs (log into the instance)
  2. Re-run the request — transient empty responses occasionally clear on retry
  3. Update pi-ai if your Devin server version changed the GetUserJwt response schema
  4. Check the Devin instance logs for why it returned an empty JWT
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the account can mint JWTs before relying on it:
const res = await fetch(`${baseUrl}/user`, { headers: { authorization: `Bearer ${apiKey}` } });
const user = await res.json();
if (!user || user.status !== "active") throw new Error("Devin account not active — cannot obtain user JWT");

Type guard

function hasUserJwt(v: unknown): v is { userJwt: string } {
  return typeof v === "object" && v !== null && typeof (v as { userJwt?: unknown }).userJwt === "string"
    && (v as { userJwt: string }).userJwt.length > 0;
}

Try / catch

try {
  const meta = await fetchDevinAuthMetadata(baseUrl, request, signal);
} catch (err) {
  if (err instanceof AIError.ProviderResponseError && err.message.includes("empty user JWT")) {
    await Bun.sleep(1000); // transient empty responses often clear
    return fetchDevinAuthMetadata(baseUrl, request, signal); // retry once
  }
  throw err;
}

Prevention

When it happens

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

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

Related errors


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