{"record":{"id":"4eecf44e6585f83c","repo":"can1357/oh-my-pi","slug":"z-ai-key-provisioning-failed-no-organization-proj","errorCode":null,"errorMessage":"Z.ai key provisioning failed: no organization/project on account","messagePattern":"Z\\.ai key provisioning failed: no organization/project on account","errorType":"exception","errorClass":"AIError.OAuthError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/registry/oauth/zai.ts","lineNumber":174,"sourceCode":" * `getCustomerInfo` → find/create the OMP-named key → obtain its secret →\n * return `${apiKey}.${secretKey}` (the 49-char durable key).\n */\nasync function mintZaiApiKey(oauthAccessToken: string, fetchImpl: FetchImpl): Promise<string> {\n\tconst bizToken = await businessLogin(oauthAccessToken, fetchImpl);\n\tconst auth = { Authorization: `Bearer ${bizToken}` };\n\n\tconst customer = unwrapEnvelope(\n\t\tawait getJson(`${BIZ_BASE}/api/biz/customer/getCustomerInfo`, auth, fetchImpl),\n\t\t\"customer lookup\",\n\t) as { organizations?: ZaiOrganization[] } | undefined;\n\tconst orgs = Array.isArray(customer?.organizations) ? customer.organizations : [];\n\tconst org = orgs.find(o => o?.isDefault) ?? orgs[0];\n\tconst projects = Array.isArray(org?.projects) ? org.projects : [];\n\tconst project = projects.find(p => p?.isDefault) ?? projects[0];\n\tconst organizationId = trimmedString(org?.organizationId);\n\tconst projectId = trimmedString(project?.projectId);\n\tif (!organizationId || !projectId) {\n\t\tthrow new AIError.OAuthError(\"Z.ai key provisioning failed: no organization/project on account\", {\n\t\t\tkind: \"token-exchange\",\n\t\t\tprovider: \"zai\",\n\t\t});\n\t}\n\n\tconst keysUrl = `${BIZ_BASE}/api/biz/v1/organization/${organizationId}/projects/${projectId}/api_keys`;\n\tconst existing = asKeyArray(unwrapEnvelope(await getJson(keysUrl, auth, fetchImpl), \"api key list\")).find(\n\t\tkey => key.name === KEY_NAME,\n\t);\n\tconst keyRecord =\n\t\texisting ??\n\t\t(unwrapEnvelope(await postJson(keysUrl, { name: KEY_NAME }, auth, fetchImpl), \"api key create\") as\n\t\t\t| Record<string, unknown>\n\t\t\t| undefined);\n\n\tconst apiKey = trimmedString(keyRecord?.apiKey);\n\tif (!apiKey) {\n\t\tthrow new AIError.OAuthError(\"Z.ai key provisioning returned no apiKey\", {","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/registry/oauth/zai.ts#L156-L192","documentation":"mintZaiApiKey lists the account's organizations and picks the default (or first) org and project. If no organization or project yields a non-empty organizationId/projectId, key provisioning cannot proceed and OAuthError is thrown. The account simply has no provisioned org/project hierarchy to attach an API key to.","triggerScenarios":"Org list returns empty array; the only org has no projects array; ids are present but empty/non-string so trimmedString returns undefined.","commonSituations":"Brand-new Z.ai account that never created an organization/project; enterprise account where project creation is restricted to admins; API returning a changed shape (projects nested differently).","solutions":["Log into the Z.ai console and create an organization and a project before running the login flow.","Re-run the OAuth login after provisioning — the listing will then resolve org/project.","If you are not an org admin, ask an admin to grant your account project membership.","Inspect the raw org list response to rule out a schema change; update the library if Z.ai renamed fields."],"exampleFix":"// before\nconst biz = await mintZaiApiKey(oauthToken, fetch); // throws on fresh account\n// after\nawait ensureZaiOrgAndProject(oauthToken); // creates org/project via console/API if missing\nconst biz = await mintZaiApiKey(oauthToken, fetch);","handlingStrategy":"validation","validationCode":"const orgs = await listZaiOrgs(token, fetch);\nconst org = orgs.find(o => o.isDefault) ?? orgs[0];\nif (!org?.organizationId || !(org.projects ?? []).length) throw new Error(\"Z.ai account has no organization/project; create one in the console first\");","typeGuard":"function hasProvisioning(org: unknown): org is { organizationId: string; projects: { projectId: string }[] } {\n  const o = org as { organizationId?: unknown; projects?: unknown };\n  return typeof o?.organizationId === \"string\" && o.organizationId.length > 0 && Array.isArray(o.projects) && o.projects.length > 0;\n}","tryCatchPattern":"try { return await mintZaiApiKey(token, fetch); }\ncatch (e) { if (e instanceof AIError.OAuthError && e.message.includes(\"no organization/project\")) return guideUserToConsole(); throw e; }","preventionTips":["Provision an organization and project in the Z.ai console before automated login","Ensure the OAuth user has project membership (not just org viewer)","Detect fresh accounts and route them through a setup wizard"],"tags":["zai","provisioning","organization","project","account-setup"],"backgroundTag":"missing-provisioning-resource","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}