Wei-Shaw/sub2api · error

agent identity 缺少必要字段

Error message

agent identity 缺少必要字段

What it means

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.

Source

Thrown at backend/internal/handler/admin/account_codex_import.go:519

	switch raw := entry.Value.(type) {
	case string:
		item.AccessToken = strings.TrimSpace(raw)
	case map[string]any:
		if agentIdentity, ok := firstCodexMap(raw, []string{"agent_identity"}, []string{"agentIdentity"}); ok || strings.EqualFold(firstCodexString(raw, []string{"auth_mode"}, []string{"authMode"}), service.OpenAIAuthModeAgentIdentity) {
			if !ok {
				agentIdentity = raw
			}
			item.IsAgentIdentity = true
			item.AgentRuntimeID = firstCodexString(agentIdentity, []string{"agent_runtime_id"}, []string{"agentRuntimeId"})
			item.AgentPrivateKey = firstCodexString(agentIdentity, []string{"agent_private_key"}, []string{"agentPrivateKey"})
			item.AgentTaskID = firstCodexString(agentIdentity, []string{"task_id"}, []string{"taskId"})
			item.AccountID = firstCodexString(agentIdentity, []string{"account_id"}, []string{"accountId"})
			item.UserID = firstCodexString(agentIdentity, []string{"chatgpt_user_id"}, []string{"chatgptUserId"})
			item.Email = firstCodexString(agentIdentity, []string{"email"})
			item.PlanType = firstCodexString(agentIdentity, []string{"plan_type"}, []string{"planType"})
			item.AgentFedRAMP = firstCodexBool(agentIdentity, []string{"chatgpt_account_is_fedramp"}, []string{"chatgptAccountIsFedramp"})
			if item.AgentRuntimeID == "" || item.AgentPrivateKey == "" || item.AccountID == "" || item.UserID == "" {
				return nil, errors.New("agent identity 缺少必要字段")
			}
			if err := service.ValidateOpenAIAgentIdentityPrivateKey(item.AgentPrivateKey); err != nil {
				return nil, errors.New("agent identity private key 格式无效")
			}
			item.Credentials["auth_mode"] = service.OpenAIAuthModeAgentIdentity
			item.Credentials["agent_runtime_id"] = item.AgentRuntimeID
			item.Credentials["agent_private_key"] = item.AgentPrivateKey
			item.Credentials["chatgpt_account_id"] = item.AccountID
			item.Credentials["chatgpt_user_id"] = item.UserID
			item.Credentials["chatgpt_account_is_fedramp"] = item.AgentFedRAMP
			setCodexCredentialIfNotEmpty(item.Credentials, "task_id", item.AgentTaskID)
			setCodexCredentialIfNotEmpty(item.Credentials, "email", item.Email)
			setCodexCredentialIfNotEmpty(item.Credentials, "plan_type", item.PlanType)
			if item.AgentTaskID == "" {
				item.WarningTexts = append(item.WarningTexts, "未包含 task_id,首次请求会使用现有 runtime 注册新 task")
			}
			item.IdentityKeys = buildCodexAgentIdentityKeys(item.AccountID)
			item.Name = buildCodexImportAccountName(item, entry.Index)

View on GitHub (pinned to 073e92d171)

Solutions

  1. 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).
  2. Check spelling/casing of keys — only the two documented spellings are recognized.
  3. If the JSON is nested, confirm the identity fields sit where the parser expects them, not one level off.
  4. If you meant a normal OAuth account, remove the agent-identity marker so the entry is not parsed as IsAgentIdentity.

Example fix

// before
{
  "agent_runtime_id": "rt_123",
  "agent_private_key": "",
  "account_id": "acc_1",
  "chatgpt_user_id": "user_1"
}

// after
{
  "agent_runtime_id": "rt_123",
  "agent_private_key": "-----BEGIN PRIVATE KEY-----...",
  "account_id": "acc_1",
  "chatgpt_user_id": "user_1",
  "task_id": "task_9",
  "email": "agent@example.com"
}
Defensive patterns

Strategy: validation

Validate before calling

function hasAgentIdentityRequiredFields(identity: Record<string, unknown>): boolean {
  const pick = (snake: string, camel: string) => {
    const v = identity[snake] ?? identity[camel]
    return typeof v === 'string' && v.length > 0
  }
  return (
    pick('agent_runtime_id', 'agentRuntimeId') &&
    pick('agent_private_key', 'agentPrivateKey') &&
    pick('account_id', 'accountId') &&
    pick('chatgpt_user_id', 'chatgptUserId')
  )
}

Type guard

function isCompleteAgentIdentity(v: unknown): v is { agent_runtime_id: string; agent_private_key: string; account_id: string; chatgpt_user_id: string } {
  if (typeof v !== 'object' || v === null) return false
  const o = v as Record<string, unknown>
  return ['agent_runtime_id', 'agent_private_key', 'account_id', 'chatgpt_user_id'].every(
    (k) => typeof o[k] === 'string' && (o[k] as string).length > 0
  )
}

Prevention

When it happens

Trigger: 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').

Common situations: 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.

Related errors


AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15). Data as JSON: /api/errors/0c029c93582d9f82. Report an issue: GitHub.