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

  1. Populate credentials with at least one key/value appropriate to the type (e.g. access_token for oauth, api_key for api_key).
  2. If credentials were removed for sharing, re-add them before import or use the redacted-export flow if one exists.
  3. 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

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


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