{"record":{"id":"0c029c93582d9f82","repo":"Wei-Shaw/sub2api","slug":"agent-identity","errorCode":null,"errorMessage":"agent identity 缺少必要字段","messagePattern":"agent identity 缺少必要字段","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/internal/handler/admin/account_codex_import.go","lineNumber":519,"sourceCode":"\tswitch raw := entry.Value.(type) {\n\tcase string:\n\t\titem.AccessToken = strings.TrimSpace(raw)\n\tcase map[string]any:\n\t\tif agentIdentity, ok := firstCodexMap(raw, []string{\"agent_identity\"}, []string{\"agentIdentity\"}); ok || strings.EqualFold(firstCodexString(raw, []string{\"auth_mode\"}, []string{\"authMode\"}), service.OpenAIAuthModeAgentIdentity) {\n\t\t\tif !ok {\n\t\t\t\tagentIdentity = raw\n\t\t\t}\n\t\t\titem.IsAgentIdentity = true\n\t\t\titem.AgentRuntimeID = firstCodexString(agentIdentity, []string{\"agent_runtime_id\"}, []string{\"agentRuntimeId\"})\n\t\t\titem.AgentPrivateKey = firstCodexString(agentIdentity, []string{\"agent_private_key\"}, []string{\"agentPrivateKey\"})\n\t\t\titem.AgentTaskID = firstCodexString(agentIdentity, []string{\"task_id\"}, []string{\"taskId\"})\n\t\t\titem.AccountID = firstCodexString(agentIdentity, []string{\"account_id\"}, []string{\"accountId\"})\n\t\t\titem.UserID = firstCodexString(agentIdentity, []string{\"chatgpt_user_id\"}, []string{\"chatgptUserId\"})\n\t\t\titem.Email = firstCodexString(agentIdentity, []string{\"email\"})\n\t\t\titem.PlanType = firstCodexString(agentIdentity, []string{\"plan_type\"}, []string{\"planType\"})\n\t\t\titem.AgentFedRAMP = firstCodexBool(agentIdentity, []string{\"chatgpt_account_is_fedramp\"}, []string{\"chatgptAccountIsFedramp\"})\n\t\t\tif item.AgentRuntimeID == \"\" || item.AgentPrivateKey == \"\" || item.AccountID == \"\" || item.UserID == \"\" {\n\t\t\t\treturn nil, errors.New(\"agent identity 缺少必要字段\")\n\t\t\t}\n\t\t\tif err := service.ValidateOpenAIAgentIdentityPrivateKey(item.AgentPrivateKey); err != nil {\n\t\t\t\treturn nil, errors.New(\"agent identity private key 格式无效\")\n\t\t\t}\n\t\t\titem.Credentials[\"auth_mode\"] = service.OpenAIAuthModeAgentIdentity\n\t\t\titem.Credentials[\"agent_runtime_id\"] = item.AgentRuntimeID\n\t\t\titem.Credentials[\"agent_private_key\"] = item.AgentPrivateKey\n\t\t\titem.Credentials[\"chatgpt_account_id\"] = item.AccountID\n\t\t\titem.Credentials[\"chatgpt_user_id\"] = item.UserID\n\t\t\titem.Credentials[\"chatgpt_account_is_fedramp\"] = item.AgentFedRAMP\n\t\t\tsetCodexCredentialIfNotEmpty(item.Credentials, \"task_id\", item.AgentTaskID)\n\t\t\tsetCodexCredentialIfNotEmpty(item.Credentials, \"email\", item.Email)\n\t\t\tsetCodexCredentialIfNotEmpty(item.Credentials, \"plan_type\", item.PlanType)\n\t\t\tif item.AgentTaskID == \"\" {\n\t\t\t\titem.WarningTexts = append(item.WarningTexts, \"未包含 task_id，首次请求会使用现有 runtime 注册新 task\")\n\t\t\t}\n\t\t\titem.IdentityKeys = buildCodexAgentIdentityKeys(item.AccountID)\n\t\t\titem.Name = buildCodexImportAccountName(item, entry.Index)","sourceCodeStart":501,"sourceCodeEnd":537,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/backend/internal/handler/admin/account_codex_import.go#L501-L537","documentation":"Returned while normalizing an agent-identity entry in the Codex import (backend/internal/handler/admin/account_codex_import.go:519) when any of the four mandatory fields is missing after snake_case/camelCase lookup: agent_runtime_id, agent_private_key, account_id, or chatgpt_user_id (item.AgentRuntimeID, item.AgentPrivateKey, item.AccountID, item.UserID). Optional fields like task_id and email do not trigger it. The check runs only for entries flagged IsAgentIdentity=true.","triggerScenarios":"Importing an agent-identity JSON where agent_runtime_id, agent_private_key, account_id, or chatgpt_user_id is absent, null, empty, or misspelled so neither the snake_case nor camelCase key matches (e.g. 'runtimeId' instead of 'agentRuntimeId').","commonSituations":"Hand-editing an exported agent identity and dropping a field; upstream format change renaming keys; copying an example template with placeholders left blank; mixing agent-identity docs with regular OAuth auth.json and missing the nested identity object.","solutions":["Ensure all four required keys exist and are non-empty strings: agent_runtime_id, agent_private_key, account_id, chatgpt_user_id (camelCase variants agentRuntimeId/agentPrivateKey/accountId/chatgptUserId also accepted).","Check spelling/casing of keys — only the two documented spellings are recognized.","If the JSON is nested, confirm the identity fields sit where the parser expects them, not one level off.","If you meant a normal OAuth account, remove the agent-identity marker so the entry is not parsed as IsAgentIdentity."],"exampleFix":"// before\n{\n  \"agent_runtime_id\": \"rt_123\",\n  \"agent_private_key\": \"\",\n  \"account_id\": \"acc_1\",\n  \"chatgpt_user_id\": \"user_1\"\n}\n\n// after\n{\n  \"agent_runtime_id\": \"rt_123\",\n  \"agent_private_key\": \"-----BEGIN PRIVATE KEY-----...\",\n  \"account_id\": \"acc_1\",\n  \"chatgpt_user_id\": \"user_1\",\n  \"task_id\": \"task_9\",\n  \"email\": \"agent@example.com\"\n}","handlingStrategy":"validation","validationCode":"function hasAgentIdentityRequiredFields(identity: Record<string, unknown>): boolean {\n  const pick = (snake: string, camel: string) => {\n    const v = identity[snake] ?? identity[camel]\n    return typeof v === 'string' && v.length > 0\n  }\n  return (\n    pick('agent_runtime_id', 'agentRuntimeId') &&\n    pick('agent_private_key', 'agentPrivateKey') &&\n    pick('account_id', 'accountId') &&\n    pick('chatgpt_user_id', 'chatgptUserId')\n  )\n}","typeGuard":"function isCompleteAgentIdentity(v: unknown): v is { agent_runtime_id: string; agent_private_key: string; account_id: string; chatgpt_user_id: string } {\n  if (typeof v !== 'object' || v === null) return false\n  const o = v as Record<string, unknown>\n  return ['agent_runtime_id', 'agent_private_key', 'account_id', 'chatgpt_user_id'].every(\n    (k) => typeof o[k] === 'string' && (o[k] as string).length > 0\n  )\n}","tryCatchPattern":null,"preventionTips":["Import the agent-identity file exactly as exported by the producing tool; avoid hand-editing.","Use only the two accepted spellings per field (snake_case or the documented camelCase variant).","Validate the four required keys in the admin UI before submit.","Remember task_id and email are optional — their absence yields only a warning, not this error."],"tags":["admin","import","agent-identity","validation","backend","codex"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}