OpenNHP/opennhp · error
could not create request
Error message
could not create request: %v
What it means
After the multipart body is built, UploadFileToNHPServer constructs the POST request with http.NewRequest("POST", httpHost+"storage/upload", body). http.NewRequest returns an error for a malformed URL or unsupported method/protocol, and the function wraps it as "could not create request: %v". The upload never leaves the client machine.
Solutions
- Print/validate the final uploadUrl (httpHost + "storage/upload") with url.Parse and inspect the wrapped error for the exact parse failure
- Fix the server peer Host value in the daemon's configuration so it is a bare host[:port] without scheme, spaces, or control characters
- Guard before calling: skip or fail fast if a.GetServerPeer().Host() is empty or fails url.Parse
- Ensure the HTTPS fallback at utils.go:201 preserves a valid host; the 400-probe only changes the scheme, so a broken host remains broken
Example fix
// before
uploadUrl := httpHost + "storage/upload"
req, err := http.NewRequest("POST", uploadUrl, body)
// after
uploadUrl := httpHost + "storage/upload"
if _, err := url.Parse(uploadUrl); err != nil {
return "", fmt.Errorf("invalid upload url %q: %v", uploadUrl, err)
}
req, err := http.NewRequest("POST", uploadUrl, body) Defensive patterns
Strategy: validation
Validate before calling
host := device.GetServerPeer().Host()
if host == "" {
return fmt.Errorf("server peer host is not configured")
}
if strings.Contains(host, "://") {
return fmt.Errorf("server peer host must not include a scheme: %q", host)
}
probeUrl := "http://" + host + "/"
if _, err := url.Parse(probeUrl + "storage/upload"); err != nil {
return fmt.Errorf("invalid upload url derived from host %q: %v", host, err)
} Type guard
func isValidUploadHost(host string) bool {
if host == "" || strings.Contains(host, "://") || strings.ContainsAny(host, " \t\r\n") {
return false
}
_, err := url.Parse("http://" + host + "/storage/upload")
return err == nil
} Try / catch
result, err := device.UploadFileToNHPServer(filePath)
if err != nil && strings.Contains(err.Error(), "could not create request") {
return fmt.Errorf("check server peer Host in config (got %q): %w", device.GetServerPeer().Host(), err)
} Prevention
- Store bare host[:port] (no scheme) in the peer table the same way the code expects
- Validate peer config at daemon startup, not at first upload
- Never interpolate user-supplied strings into the host field
- Add a startup smoke test that performs a trivial HTTP GET against the configured host
When it happens
Trigger: The server peer host configured on the UdpDevice produces an invalid URL: httpHost is built as fmt.Sprintf("http://%s/", a.GetServerPeer().Host()) at utils.go:194 (or https at line 201 after a 400 fallback), then "storage/upload" is appended. An empty, malformed (bad characters, spaces, control chars), or wrongly-schemed host makes http.NewRequest fail. A nil body also errors, but body is always a valid *bytes.Buffer here.
Common situations: Misconfigured server address in the peer table (config.toml/server.toml) — empty host, host containing "http://" prefix duplicated (e.g. "http://http://..."), spaces, or trailing invalid characters; url.Parse failures like "net/url: invalid control character in URL"; missing Host() configuration so the URL is "http:///storage/upload".
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/401c82aad7f054ee.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/db/utils.go:249
Reader: file,
Progress: progress,
}
_, err = io.Copy(part, progressReader)
if err != nil {
return "", fmt.Errorf("could not copy file to server: %v", err)
}
err = writer.Close()
if err != nil {
return "", fmt.Errorf("could not close writer: %v", err)
}
uploadUrl := httpHost + "storage/upload"
req, err := http.NewRequest("POST", uploadUrl, body)
if err != nil {
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))View on GitHub (pinned to 6e04ca5ff0)