{"record":{"id":"f1ab4e618faf36ea","repo":"router-for-me/CLIProxyAPI","slug":"no-file-uploaded","errorCode":null,"errorMessage":"no file uploaded","messagePattern":"no file uploaded","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"internal/api/handlers/management/auth_files_crud.go","lineNumber":239,"sourceCode":"\t\treturn nil, nil\n\t}\n\n\tkeys := make([]string, 0, len(form.File))\n\tfor key := range form.File {\n\t\tkeys = append(keys, key)\n\t}\n\tsort.Strings(keys)\n\n\theaders := make([]*multipart.FileHeader, 0)\n\tfor _, key := range keys {\n\t\theaders = append(headers, form.File[key]...)\n\t}\n\treturn headers, nil\n}\n\nfunc (h *Handler) storeUploadedAuthFile(ctx context.Context, file *multipart.FileHeader) (string, error) {\n\tif file == nil {\n\t\treturn \"\", fmt.Errorf(\"no file uploaded\")\n\t}\n\tname := filepath.Base(strings.TrimSpace(file.Filename))\n\tif !strings.HasSuffix(strings.ToLower(name), \".json\") {\n\t\treturn \"\", errAuthFileMustBeJSON\n\t}\n\tsrc, err := file.Open()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to open uploaded file: %w\", err)\n\t}\n\tdefer src.Close()\n\n\tdata, err := io.ReadAll(src)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to read uploaded file: %w\", err)\n\t}\n\tif err := h.writeAuthFile(ctx, name, data); err != nil {\n\t\treturn \"\", err\n\t}","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/api/handlers/management/auth_files_crud.go#L221-L257","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\n$ curl -X POST http://127.0.0.1:8000/v0/management/auth-files -H 'Content-Type: application/json' -d '{}'\n\n# after\n$ curl -X POST http://127.0.0.1:8000/v0/management/auth-files -F 'file=@my-codex-auth.json'","handlingStrategy":"validation","validationCode":"// Client-side pre-check before POSTing\ntype uploadReq struct{ File *os.File }\nfunc validUpload(r uploadReq) bool { return r.File != nil }","typeGuard":"func isNoFileUploaded(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"no file uploaded\")\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["management-api","upload","multipart","validation"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}