router-for-me/CLIProxyAPI · error
no file uploaded
Error message
no file uploaded
What it means
storeUploadedAuthFile in internal/api/handlers/management/auth_files_crud.go handles multipart uploads of auth files to the management API. If the caller invokes the upload endpoint without any file part (file == nil), it rejects with `no file uploaded`. The multipart form parsing succeeded but no usable FileHeader was extracted, meaning the request was not a proper multipart file upload.
Source
Thrown at internal/api/handlers/management/auth_files_crud.go:239
return nil, nil
}
keys := make([]string, 0, len(form.File))
for key := range form.File {
keys = append(keys, key)
}
sort.Strings(keys)
headers := make([]*multipart.FileHeader, 0)
for _, key := range keys {
headers = append(headers, form.File[key]...)
}
return headers, nil
}
func (h *Handler) storeUploadedAuthFile(ctx context.Context, file *multipart.FileHeader) (string, error) {
if file == nil {
return "", fmt.Errorf("no file uploaded")
}
name := filepath.Base(strings.TrimSpace(file.Filename))
if !strings.HasSuffix(strings.ToLower(name), ".json") {
return "", errAuthFileMustBeJSON
}
src, err := file.Open()
if err != nil {
return "", fmt.Errorf("failed to open uploaded file: %w", err)
}
defer src.Close()
data, err := io.ReadAll(src)
if err != nil {
return "", fmt.Errorf("failed to read uploaded file: %w", err)
}
if err := h.writeAuthFile(ctx, name, data); err != nil {
return "", err
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Send the request as multipart/form-data with the file under the expected field name (e.g. curl -F 'file=@auths/my.json').
- Verify the client HTTP library is not overriding Content-Type or stripping the form.
- Check the route definition for the exact form field name expected by the handler.
- Ensure the file part is non-empty — a named but empty part may also surface here depending on form parsing.
Example fix
# before
$ curl -X POST http://127.0.0.1:8000/v0/management/auth-files -H 'Content-Type: application/json' -d '{}'
# after
$ curl -X POST http://127.0.0.1:8000/v0/management/auth-files -F 'file=@my-codex-auth.json' Defensive patterns
Strategy: validation
Validate before calling
// Client-side pre-check before POSTing
type uploadReq struct{ File *os.File }
func validUpload(r uploadReq) bool { return r.File != nil } Type guard
func isNoFileUploaded(err error) bool {
return err != nil && strings.Contains(err.Error(), "no file uploaded")
} Prevention
- Always use multipart/form-data with a real file part for upload endpoints.
- Automate uploads with curl -F 'file=@...' to avoid content-type mistakes.
- Assert the chosen form field name matches the route's expectation.
When it happens
Trigger: POST to the management auth-file upload route with no `file` form part (empty body, wrong field name, or JSON body instead of multipart/form-data); sending metadata fields only; client code forgetting to attach the file.
Common situations: Automation/curl scripts that omit -F file=@...; frontend forms using the wrong input name; content-type header set to application/json by an HTTP client wrapper while the endpoint expects multipart.
Related errors
- failed to open uploaded file: %w
- auth path is empty
- failed to read uploaded file: %w
- failed to write file: %w
- invalid request body
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/f1ab4e618faf36ea.
Report an issue: GitHub.