{"record":{"id":"fe5f7814944ba5da","repo":"Wei-Shaw/sub2api","slug":"account-type-is-required","errorCode":null,"errorMessage":"account type is required","messagePattern":"account type is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/internal/handler/admin/account_data.go","lineNumber":686,"sourceCode":"\t}\n\tif item.Status != \"\" {\n\t\tnormalizedStatus := normalizeProxyStatus(item.Status)\n\t\tif normalizedStatus != service.StatusActive && normalizedStatus != \"inactive\" {\n\t\t\treturn fmt.Errorf(\"proxy status is invalid: %s\", item.Status)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validateDataAccount(item DataAccount) error {\n\tif strings.TrimSpace(item.Name) == \"\" {\n\t\treturn errors.New(\"account name is required\")\n\t}\n\tif strings.TrimSpace(item.Platform) == \"\" {\n\t\treturn errors.New(\"account platform is required\")\n\t}\n\tif strings.TrimSpace(item.Type) == \"\" {\n\t\treturn errors.New(\"account type is required\")\n\t}\n\tif len(item.Credentials) == 0 {\n\t\treturn errors.New(\"account credentials is required\")\n\t}\n\tswitch item.Type {\n\tcase service.AccountTypeOAuth, service.AccountTypeSetupToken, service.AccountTypeAPIKey, service.AccountTypeUpstream:\n\tdefault:\n\t\treturn fmt.Errorf(\"account type is invalid: %s\", item.Type)\n\t}\n\tif item.RateMultiplier != nil && *item.RateMultiplier < 0 {\n\t\treturn errors.New(\"rate_multiplier must be >= 0\")\n\t}\n\tif item.Concurrency < 0 {\n\t\treturn errors.New(\"concurrency must be >= 0\")\n\t}\n\tif item.Priority < 0 {\n\t\treturn errors.New(\"priority must be >= 0\")\n\t}","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/backend/internal/handler/admin/account_data.go#L668-L704","documentation":"Returned by validateDataAccount (backend/internal/handler/admin/account_data.go:686) when an accounts[] entry has name and platform but an empty type after TrimSpace. Type must then be one of the allowed values (oauth, setup_token, api_key, upstream — anything else yields the separate 'account type is invalid' error).","triggerScenarios":"An account object with the type key missing or blank; a numeric/boolean type that fails to deserialize into the string field, leaving it empty.","commonSituations":"Payloads converted from YAML/CSV where the type column was empty; enum values quoted differently; new account kinds not yet supported by this backend version.","solutions":["Set type to one of the supported values: oauth, setup_token, api_key, or upstream.","Verify the string exactly matches (lowercase, underscore style).","If importing a new account kind, upgrade the backend or convert the entry to a supported type."],"exampleFix":"// before\n{ \"name\": \"main\", \"platform\": \"openai\", \"credentials\": { ... } }\n\n// after\n{ \"name\": \"main\", \"platform\": \"openai\", \"type\": \"oauth\", \"credentials\": { ... } }","handlingStrategy":"type-guard","validationCode":"const ACCOUNT_TYPES = new Set(['oauth', 'setup_token', 'api_key', 'upstream'])\nfunction hasValidAccountType(entry: Record<string, unknown>): boolean {\n  return typeof entry.type === 'string' && ACCOUNT_TYPES.has(entry.type)\n}","typeGuard":"const ACCOUNT_TYPES = ['oauth', 'setup_token', 'api_key', 'upstream'] as const\nfunction isAccountType(t: unknown): t is (typeof ACCOUNT_TYPES)[number] {\n  return typeof t === 'string' && (ACCOUNT_TYPES as readonly string[]).includes(t)\n}","tryCatchPattern":null,"preventionTips":["Use the exact lowercase identifiers from service.AccountType* constants.","Reject unknown types client-side with a dropdown instead of free text.","When new account kinds appear upstream, confirm this backend version supports them before importing."],"tags":["admin","import","account","validation","backend","enum"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}