can1357/oh-my-pi · error · ProviderHttpError

Umans usage endpoint returned ${response.status} ${response.

Error message

Umans usage endpoint returned ${response.status} ${response.statusText}

What it means

Thrown by fetchUmansUsage when the Umans usage endpoint returns 401 (invalid key) or 403 (forbidden). As with OpenCode Go, throwing is intentional so credential probing distinguishes a definitively bad key (ok:false) from transient failures, which return null instead. The message carries the HTTP status and status text.

Source

Thrown at packages/ai/src/usage/umans.ts:214

	const credential = params.credential;
	if (credential.type !== "api_key" || !credential.apiKey) return null;

	const baseUrl = normalizeBaseUrl(params.baseUrl);
	const url = `${baseUrl}${USAGE_PATH}`;
	const headers: Record<string, string> = {
		authorization: `Bearer ${credential.apiKey}`,
		accept: "application/json",
	};

	let payload: UmansUsagePayload | null = null;
	try {
		const response = await ctx.fetch(url, { headers, signal: params.signal });
		if (!response.ok) {
			// Auth failures (401/403) must throw so checkCredentials flags the bad
			// key as ok:false rather than ok:null (unknown). Other non-ok statuses
			// are transient — return null so the probe reports "no data".
			if (response.status === 401 || response.status === 403) {
				throw new ProviderHttpError(
					`Umans usage endpoint returned ${response.status} ${response.statusText}`.trim(),
					response.status,
				);
			}
			ctx.logger?.warn("Umans usage fetch failed", { status: response.status, statusText: response.statusText });
			return null;
		}
		const json = (await response.json()) as unknown;
		if (!isRecord(json)) {
			ctx.logger?.warn("Umans usage response was not a JSON object");
			return null;
		}
		payload = json as unknown as UmansUsagePayload;
	} catch (error) {
		// Re-throw auth errors so the credential-health probe can surface them.
		if (error instanceof ProviderHttpError) throw error;
		ctx.logger?.warn("Umans usage fetch error", { error: String(error) });
		return null;

View on GitHub (pinned to 9690622007)

Solutions

  1. For 401, obtain and configure a fresh Umans API key.
  2. For 403, confirm the account/role has permission to read usage data or the required subscription.
  3. Verify the key matches the intended Umans environment (staging keys fail in production).
  4. Trim stray whitespace/quotes from the key value in env or config.

Example fix

// before: unconfigured
const params = { /* no apiKey */ };
// after
const params = { apiKey: process.env.UMANS_API_KEY! };
if (!params.apiKey) throw new Error("UMANS_API_KEY is not set");
Defensive patterns

Strategy: validation

Validate before calling

const key = process.env.UMANS_API_KEY?.trim();
if (!key) throw new Error("UMANS_API_KEY is required");
// verify entitlement once at boot
const cred = await umansProvider.checkCredentials();
if (cred.ok === false) throw new Error("Umans key rejected (401/403): check key and permissions");

Try / catch

try {
	const usage = await umansProvider.fetchUsage(params);
} catch (err) {
	if (err instanceof AIError.ProviderHttpError && (err.status === 401 || err.status === 403)) {
		// definitive credential failure — disable integration, alert operator
	} else throw err; // null return means transient; safe to ignore
}

Prevention

When it happens

Trigger: Usage fetch or checkCredentials against the Umans endpoint with a missing, expired, or revoked API key (401), or a key lacking permission/entitlement for usage data (403).

Common situations: UMANS_API_KEY not configured in the environment; key invalidated after team/workspace changes; account without the entitlement that exposes usage; key from a different environment (staging vs production).

Related errors


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