router-for-me/CLIProxyAPI · error

auth file name must end with .json

Error message

auth file name must end with .json

What it means

Thrown by validateHostAuthSaveRequest when the (safe) file name does not end with .json (checked case-insensitively). Auth files must be JSON files so the loader and watchers can parse them; other extensions are rejected at save time.

Source

Thrown at internal/pluginhost/auth_callbacks.go:268

		return nil, nil, fmt.Errorf("failed to read auth file: %w", errRead)
	}
	if len(bytesTrimSpace(data)) == 0 {
		return nil, nil, fmt.Errorf("auth file is empty for auth_index %s", authIndex)
	}
	var metadata map[string]any
	if errUnmarshal := json.Unmarshal(data, &metadata); errUnmarshal != nil {
		return nil, nil, fmt.Errorf("invalid auth file for auth_index %s: %w", authIndex, errUnmarshal)
	}
	return auth, data, nil
}

func validateHostAuthSaveRequest(req pluginapi.HostAuthSaveRequest) (string, []byte, error) {
	name := strings.TrimSpace(req.Name)
	if isUnsafeAuthFileName(name) {
		return "", nil, fmt.Errorf("invalid auth file name")
	}
	if !strings.HasSuffix(strings.ToLower(name), ".json") {
		return "", nil, fmt.Errorf("auth file name must end with .json")
	}
	rawJSON := bytesTrimSpace(req.JSON)
	if len(rawJSON) == 0 {
		return "", nil, fmt.Errorf("json is required")
	}
	var metadata map[string]any
	if errUnmarshal := json.Unmarshal(rawJSON, &metadata); errUnmarshal != nil {
		return "", nil, fmt.Errorf("invalid auth json: %w", errUnmarshal)
	}
	return filepath.Base(name), rawJSON, nil
}

func (h *Host) saveAuthFile(ctx context.Context, name string, data []byte) (string, error) {
	authDir := h.resolvedAuthDir()
	if authDir == "" {
		return "", fmt.Errorf("auth directory is unavailable")
	}
	dst := filepath.Join(authDir, filepath.Base(name))

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Append .json to the name before calling save if missing
  2. Derive names from an existing listing (listAuthFiles returns *.json names) to match the convention

Example fix

// before
name := "openai-credentials"

// after
if !strings.HasSuffix(strings.ToLower(name), ".json") {
    name += ".json"
}
Defensive patterns

Strategy: validation

Validate before calling

if !strings.HasSuffix(strings.ToLower(name), ".json") {
    name += ".json"
}

Prevention

When it happens

Trigger: Plugin submits name 'credentials', 'auth.txt', or 'auth.JSON5' — anything whose lowercase form lacks the .json suffix.

Common situations: Plugin derives the extension from a provider config value; version bump of a plugin changed its naming convention; copy-paste of a non-Go filename convention.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/24ab2daab143c2e5. Report an issue: GitHub.