can1357/oh-my-pi · error · AIError.OAuthError
Z.ai key provisioning returned no apiKey
Error message
Z.ai key provisioning returned no apiKey
What it means
After creating the API key, mintZaiApiKey unwraps the create response and requires a non-empty apiKey string field. If the record lacks it (or it's non-string/empty), OAuthError is thrown. The create call succeeded at HTTP/envelope level but did not return the expected key identifier.
Source
Thrown at packages/ai/src/registry/oauth/zai.ts:192
throw new AIError.OAuthError("Z.ai key provisioning failed: no organization/project on account", {
kind: "token-exchange",
provider: "zai",
});
}
const keysUrl = `${BIZ_BASE}/api/biz/v1/organization/${organizationId}/projects/${projectId}/api_keys`;
const existing = asKeyArray(unwrapEnvelope(await getJson(keysUrl, auth, fetchImpl), "api key list")).find(
key => key.name === KEY_NAME,
);
const keyRecord =
existing ??
(unwrapEnvelope(await postJson(keysUrl, { name: KEY_NAME }, auth, fetchImpl), "api key create") as
| Record<string, unknown>
| undefined);
const apiKey = trimmedString(keyRecord?.apiKey);
if (!apiKey) {
throw new AIError.OAuthError("Z.ai key provisioning returned no apiKey", {
kind: "token-exchange",
provider: "zai",
});
}
// Always fetch the secret via the copy endpoint: list entries mask it
// (`*****abcd`) and the create response's inline secret is not reliable
// across account states, whereas copy always returns the full secret.
const copied = unwrapEnvelope(
await getJson(`${keysUrl}/copy/${encodeURIComponent(apiKey)}`, auth, fetchImpl),
"api key copy",
) as { secretKey?: unknown } | undefined;
const secretKey = trimmedString(copied?.secretKey);
if (!secretKey) {
throw new AIError.OAuthError("Z.ai key provisioning returned no secretKey", {
kind: "token-exchange",
provider: "zai",
});View on GitHub (pinned to 9690622007)
Solutions
- Log the raw create response to see the actual field names; update the library or parse the alternative field if Z.ai renamed apiKey.
- Retry provisioning — transient partial responses can occur; delete orphaned keys afterward to stay under quota.
- Verify the token used has full api_keys read/write scope.
- Catch AIError.OAuthError and report provisioning as incomplete rather than treating login as failed auth.
Defensive patterns
Strategy: try-catch
Type guard
function hasApiKeyField(r: unknown): r is { apiKey: string } { return !!r && typeof r === "object" && typeof (r as Record<string, unknown>).apiKey === "string" && (r as { apiKey: string }).apiKey.length > 0; } Try / catch
try { return await mintZaiApiKey(token, fetch); }
catch (e) {
if (e instanceof AIError.OAuthError && e.message.includes("no apiKey")) {
logger.error("Z.ai key create succeeded but response lacked apiKey — check API schema/token scope");
}
throw e;
} Prevention
- Grant the token full api_keys read scope
- Keep the library updated for Z.ai response schema changes
- Log raw provisioning responses when debugging
When it happens
Trigger: Z.ai key-create endpoint returns data without apiKey (name rejected silently, async creation pending, or response schema changed so the field is named id/key instead).
Common situations: Z.ai API version drift renaming the field; creation endpoint returning a job/pending object; permission-limited token that can create but not read key material.
Related errors
- Z.ai business login returned no access token
- Z.ai key provisioning returned no secretKey
- Z.ai key provisioning failed: no organization/project on acc
- Credential ${id} is not OAuth (provider=${provider}, type=${
- Azure OpenAI API key is required. Set AZURE_OPENAI_API_KEY e
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ac9677fe4453af03.
Report an issue: GitHub.