router-for-me/CLIProxyAPI · error
json is required
Error message
json is required
What it means
Thrown by validateHostAuthSaveRequest when the request's JSON payload trims to zero length. The save callback requires a body; an empty (or whitespace-only) JSON field is rejected before any filesystem action.
Source
Thrown at internal/pluginhost/auth_callbacks.go:272
}
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))
if !filepath.IsAbs(dst) {
if abs, errAbs := filepath.Abs(dst); errAbs == nil {
dst = abs
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Marshal the auth object and assign it to req.JSON before calling save
- Add a pre-check in the plugin: len(bytes.TrimSpace(json)) > 0
- Log the request (minus secrets) when save fails to catch empty payloads early
Example fix
// before
req := pluginapi.HostAuthSaveRequest{Name: name, JSON: string(data)} // data empty
// after
if len(bytes.TrimSpace(data)) == 0 { return errors.New("nothing to save") }
req := pluginapi.HostAuthSaveRequest{Name: name, JSON: string(data)} Defensive patterns
Strategy: validation
Validate before calling
if len(bytes.TrimSpace(req.JSON)) == 0 {
return errors.New("refusing to save empty auth json")
} Prevention
- Always marshal the payload and assert non-empty before save
- Add unit tests asserting the save path rejects zero-value requests
When it happens
Trigger: Plugin sends HostAuthSaveRequest{Name: "x.json", JSON: ""} or JSON containing only whitespace/newlines.
Common situations: Plugin bug where the marshaled struct is forgotten (zero value sent); serialization step silently produced empty output; a test stub omitting the field.
Related errors
- invalid auth file name
- auth file name must end with .json
- invalid auth json: %w
- auth path is empty
- invalid auth weight: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/af462ed9c68c2e85.
Report an issue: GitHub.