Wei-Shaw/sub2api · error
account credentials is required
Error message
account credentials is required
What it means
Returned by validateDataAccount (backend/internal/handler/admin/account_data.go:689) when an accounts[] entry has name, platform, and a valid type but an empty or absent credentials map (len(item.Credentials) == 0). Credentials carries the account's secrets (tokens, API keys) and is required regardless of type.
Source
Thrown at backend/internal/handler/admin/account_data.go:689
if normalizedStatus != service.StatusActive && normalizedStatus != "inactive" {
return fmt.Errorf("proxy status is invalid: %s", item.Status)
}
}
return nil
}
func validateDataAccount(item DataAccount) error {
if strings.TrimSpace(item.Name) == "" {
return errors.New("account name is required")
}
if strings.TrimSpace(item.Platform) == "" {
return errors.New("account platform is required")
}
if strings.TrimSpace(item.Type) == "" {
return errors.New("account type is required")
}
if len(item.Credentials) == 0 {
return errors.New("account credentials is required")
}
switch item.Type {
case service.AccountTypeOAuth, service.AccountTypeSetupToken, service.AccountTypeAPIKey, service.AccountTypeUpstream:
default:
return fmt.Errorf("account type is invalid: %s", item.Type)
}
if item.RateMultiplier != nil && *item.RateMultiplier < 0 {
return errors.New("rate_multiplier must be >= 0")
}
if item.Concurrency < 0 {
return errors.New("concurrency must be >= 0")
}
if item.Priority < 0 {
return errors.New("priority must be >= 0")
}
return nil
}
View on GitHub (pinned to 073e92d171)
Solutions
- Populate credentials with at least one key/value appropriate to the type (e.g. access_token for oauth, api_key for api_key).
- If credentials were removed for sharing, re-add them before import or use the redacted-export flow if one exists.
- Confirm the field is a JSON object of strings, not null.
Example fix
// before
{ "name": "main", "platform": "openai", "type": "api_key", "credentials": {} }
// after
{ "name": "main", "platform": "openai", "type": "api_key", "credentials": { "api_key": "sk-..." } } Defensive patterns
Strategy: validation
Validate before calling
function hasCredentials(entry: Record<string, unknown>): boolean {
const c = entry.credentials
return typeof c === 'object' && c !== null && !Array.isArray(c) && Object.keys(c).length > 0 &&
Object.values(c).every((v) => typeof v === 'string')
} Type guard
function isNonEmptyCredentials(c: unknown): c is Record<string, string> {
if (typeof c !== 'object' || c === null || Array.isArray(c)) return false
const o = c as Record<string, unknown>
return Object.keys(o).length > 0 && Object.values(o).every((v) => typeof v === 'string')
} Prevention
- Never import redacted/secret-stripped exports; keep credentials in the payload.
- Serialize credentials as a flat string map (JSON object of strings).
- Check each entry's credentials is present and non-empty before submit.
When it happens
Trigger: An account object with "credentials": {} or no credentials key; credentials sent as null; a nested structure that failed to unmarshal into map[string]string leaving it empty.
Common situations: Stripping secrets before sharing an export then re-importing it; serializers omitting empty maps; credentials stored under a different key (e.g. 'secrets').
Related errors
- account name is required
- account platform is required
- account type is required
- rate_multiplier must be >= 0
- concurrency must be >= 0
AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15).
Data as JSON: /api/errors/5598eaecb8f84c04.
Report an issue: GitHub.