OpenNHP/opennhp · error
unexpected status code
Error message
unexpected status code: %d, content: %s
What it means
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.
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
Example fix
// before
if resp.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("unexpected status code: %d, content: %s", resp.StatusCode, string(bodyBytes))
}
// after
if resp.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("upload to %s failed: status %d, body: %s", uploadUrl, resp.StatusCode, string(bodyBytes))
}
// (operator fix for 413: raise nginx client_max_body_size and restart the server) Defensive patterns
Strategy: type-guard
Validate before calling
// check server exposes the endpoint and accepts your size before uploading
resp, err := http.Get("http://" + host + "/storage/upload")
if err == nil {
resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
return fmt.Errorf("server %s does not implement /storage/upload", host)
}
}
if fileInfo.Size() > maxServerUploadSize {
return fmt.Errorf("file exceeds server upload limit")
} Type guard
func isRetryableUploadStatus(code int) bool {
switch code {
case http.StatusTooManyRequests, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout:
return true
default:
return code >= 500
}
} Try / catch
result, err := device.UploadFileToNHPServer(filePath)
if err != nil {
var status int
if n, _ := fmt.Sscanf(err.Error(), "unexpected status code: %d", &status); n == 1 {
switch {
case status == http.StatusNotFound:
// wrong server version/endpoint
case status == http.StatusUnauthorized || status == http.StatusForbidden:
// add credentials
case status == http.StatusRequestEntityTooLarge:
// shrink/split file or raise server limit
case isRetryableUploadStatus(status):
// retry after delay
}
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- could not create request
- could not send https request
- could not read response body
- unexpected status code when download HRK
- unexpected status code when download hsk_cek
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/27cdacf9155d573f.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/db/utils.go:267
return "", fmt.Errorf("could not create request: %v", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
client := &http.Client{
Timeout: 120 * time.Minute,
}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("could not send https request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("unexpected status code: %d, content: %s", resp.StatusCode, string(bodyBytes))
}
// read response body
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("could not read response body: %v", err)
}
// parse response body
var respBody ServerResponse
err = json.Unmarshal(bodyBytes, &respBody)
if err != nil {
return "", fmt.Errorf("could not parse response body: %v", err)
}
duration := time.Since(startTime)
speed := float64(progress.TotalSize) / duration.Seconds() / (1024 * 1024)View on GitHub (pinned to 6e04ca5ff0)