{"record":{"id":"27cdacf9155d573f","repo":"OpenNHP/opennhp","slug":"unexpected-status-code-d-content-s","errorCode":null,"errorMessage":"unexpected status code: %d, content: %s","messagePattern":"unexpected status code: (.+?), content: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/db/utils.go","lineNumber":267,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"could not create request: %v\", err)\n\t}\n\n\treq.Header.Set(\"Content-Type\", writer.FormDataContentType())\n\n\tclient := &http.Client{\n\t\tTimeout: 120 * time.Minute,\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not send https request: %v\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tbodyBytes, _ := io.ReadAll(resp.Body)\n\n\t\treturn \"\", fmt.Errorf(\"unexpected status code: %d, content: %s\", resp.StatusCode, string(bodyBytes))\n\t}\n\n\t// read response body\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not read response body: %v\", err)\n\t}\n\n\t// parse response body\n\tvar respBody ServerResponse\n\n\terr = json.Unmarshal(bodyBytes, &respBody)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not parse response body: %v\", err)\n\t}\n\n\tduration := time.Since(startTime)\n\tspeed := float64(progress.TotalSize) / duration.Seconds() / (1024 * 1024)","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/db/utils.go#L249-L285","documentation":"The upload POST reached the server but returned a non-200 status. UploadFileToNHPServer reads the response body and returns \"unexpected status code: %d, content: %s\" embedding both the HTTP status code and the server's error payload. The request itself was delivered; the server rejected it at the application/protocol level.","triggerScenarios":"resp.StatusCode != http.StatusOK after client.Do in UploadFileToNHPServer (endpoints/db/utils.go:264-268). Typical causes: 400/404 because the \"storage/upload\" route doesn't exist on that server build, 401/403 from missing/invalid auth on the upload endpoint, 413 when the file exceeds the server's body-size limit, 5xx from a server-side failure, or the server replying 400 to the initial http:// probe (utils.go:200) which then correctly switches to https.","commonSituations":"Uploading to a server that doesn't expose /storage/upload (version mismatch); proxy or auth middleware returning 401/403; server max upload size (nginx client_max_body_size or Gin limit) rejecting large files with 413; reverse proxy returning 502/504; hitting the wrong host so an unrelated web app answers.","solutions":["Inspect the status code and the embedded content string in the error — the server's response body usually states the exact rejection reason","Verify the server actually implements POST /storage/upload and matches the client's expected ServerResponse format (version match between endpoints/db and the nhp-server build)","If the status is 413, raise the server/proxy body-size limit or split/compress the file before upload","If 401/403, add the required auth credentials/headers to the request (the current code sets only Content-Type at utils.go:252)","If 5xx, check the server logs; the client request format may violate a server-side parser expectation"],"exampleFix":"// before\nif resp.StatusCode != http.StatusOK {\n\tbodyBytes, _ := io.ReadAll(resp.Body)\n\treturn \"\", fmt.Errorf(\"unexpected status code: %d, content: %s\", resp.StatusCode, string(bodyBytes))\n}\n// after\nif resp.StatusCode != http.StatusOK {\n\tbodyBytes, _ := io.ReadAll(resp.Body)\n\treturn \"\", fmt.Errorf(\"upload to %s failed: status %d, body: %s\", uploadUrl, resp.StatusCode, string(bodyBytes))\n}\n// (operator fix for 413: raise nginx client_max_body_size and restart the server)","handlingStrategy":"type-guard","validationCode":"// check server exposes the endpoint and accepts your size before uploading\nresp, err := http.Get(\"http://\" + host + \"/storage/upload\")\nif err == nil {\n\tresp.Body.Close()\n\tif resp.StatusCode == http.StatusNotFound {\n\t\treturn fmt.Errorf(\"server %s does not implement /storage/upload\", host)\n\t}\n}\nif fileInfo.Size() > maxServerUploadSize {\n\treturn fmt.Errorf(\"file exceeds server upload limit\")\n}","typeGuard":"func isRetryableUploadStatus(code int) bool {\n\tswitch code {\n\tcase http.StatusTooManyRequests, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout:\n\t\treturn true\n\tdefault:\n\t\treturn code >= 500\n\t}\n}","tryCatchPattern":"result, err := device.UploadFileToNHPServer(filePath)\nif err != nil {\n\tvar status int\n\tif n, _ := fmt.Sscanf(err.Error(), \"unexpected status code: %d\", &status); n == 1 {\n\t\tswitch {\n\t\tcase status == http.StatusNotFound:\n\t\t\t// wrong server version/endpoint\n\t\tcase status == http.StatusUnauthorized || status == http.StatusForbidden:\n\t\t\t// add credentials\n\t\tcase status == http.StatusRequestEntityTooLarge:\n\t\t\t// shrink/split file or raise server limit\n\t\tcase isRetryableUploadStatus(status):\n\t\t\t// retry after delay\n\t\t}\n\t}\n\treturn err\n}","preventionTips":["Confirm the nhp-server build matches the endpoints/db client expectations (route + ServerResponse format)","Configure auth on the upload endpoint consistently on both sides","Raise proxy/server body-size limits for large files","Log the server-provided content string in the error — it names the exact rejection cause","Point the peer Host at the correct server; wrong hosts often answer with unexpected statuses"],"tags":["go","http","http-status","upload","server"],"backgroundTag":"http-error-response","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}