can1357/oh-my-pi · error · AIError.OAuthError
Z.ai key provisioning returned no secretKey
Error message
Z.ai key provisioning returned no secretKey
What it means
Listed key entries mask the secret, so mintZaiApiKey always fetches the plaintext via the copy endpoint (/copy/{apiKey}) and requires a non-empty secretKey in the response. If absent, OAuthError is thrown — the key identifier exists but its secret could not be retrieved, leaving an unusable half-credential.
Source
Thrown at packages/ai/src/registry/oauth/zai.ts:207
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",
});
}
return `${apiKey}.${secretKey}`;
}
export class ZaiOAuthFlow extends OAuthCallbackFlow {
#fetch: FetchImpl;
constructor(ctrl: OAuthController) {
super(ctrl, {
preferredPort: CALLBACK_PORT,
callbackPath: CALLBACK_PATH,
allowPortFallback: false,
});
this.#fetch = ctrl.fetch ?? fetch;View on GitHub (pinned to 9690622007)
Solutions
- Ensure the same regional BIZ_BASE and auth are used for create and copy; re-run the full mint flow.
- Check the account/token has permission to copy (reveal) key secrets — some roles can create but not reveal.
- Log the copy response to detect renamed fields and update the library if the schema changed.
- On failure, delete the orphaned apiKey via the API to avoid accumulating unusable keys.
Example fix
// before
const copied = await getJson(`${keysUrl}/copy/${encodeURIComponent(apiKey)}`, auth, fetch);
// after
let copied = await getJson(`${keysUrl}/copy/${encodeURIComponent(apiKey)}`, auth, fetch).catch(async e => {
await deleteZaiKey(keysUrl, apiKey, auth, fetch); // clean up unusable key
throw e;
}); Defensive patterns
Strategy: try-catch
Validate before calling
if (!apiKey) throw new Error("Cannot fetch secret: apiKey missing from create response"); Type guard
function hasSecretKey(r: unknown): r is { secretKey: string } { return !!r && typeof r === "object" && typeof (r as Record<string, unknown>).secretKey === "string" && (r as { secretKey: string }).secretKey.length > 0; } Try / catch
try { return await mintZaiApiKey(token, fetch); }
catch (e) {
if (e instanceof AIError.OAuthError && e.message.includes("no secretKey")) {
await deleteZaiKeySafely(token, apiKey).catch(() => {}); // avoid orphaned key
return retryMintOnce();
}
throw e;
} Prevention
- Use one consistent regional base URL for create and copy calls
- Verify the token can reveal (copy) key secrets, not just create
- Clean up unusable keys after failed mints to stay under quota
- Alert on this error since the key identifier exists without a retrievable secret
When it happens
Trigger: Copy endpoint returns envelope without secretKey: insufficient permission to copy, key created in a different region than the copy request, Z.ai changed the field name, or the copy endpoint rejects the URL-encoded key.
Common situations: Region mismatch between key creation and copy call; token lacking copy scope; Z.ai API schema drift; key deleted between create and copy.
Related errors
- Z.ai key provisioning returned no apiKey
- Z.ai business login returned no access token
- Z.ai key provisioning failed: no organization/project on acc
- failed to unmarshal LoadCodeAssistResponse: ${result.summary
- failed to unmarshal OnboardUser operation: ${result.summary}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3a0350a43b867a93.
Report an issue: GitHub.