{"record":{"id":"401c82aad7f054ee","repo":"OpenNHP/opennhp","slug":"could-not-create-request-v","errorCode":null,"errorMessage":"could not create request: %v","messagePattern":"could not create request: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/db/utils.go","lineNumber":249,"sourceCode":"\t\tReader:   file,\n\t\tProgress: progress,\n\t}\n\n\t_, err = io.Copy(part, progressReader)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not copy file to server: %v\", err)\n\t}\n\n\terr = writer.Close()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not close writer: %v\", err)\n\t}\n\n\tuploadUrl := httpHost + \"storage/upload\"\n\n\treq, err := http.NewRequest(\"POST\", uploadUrl, body)\n\tif err != nil {\n\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))","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/db/utils.go#L231-L267","documentation":"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.","triggerScenarios":"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.","commonSituations":"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\".","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"],"exampleFix":"// before\nuploadUrl := httpHost + \"storage/upload\"\nreq, err := http.NewRequest(\"POST\", uploadUrl, body)\n// after\nuploadUrl := httpHost + \"storage/upload\"\nif _, err := url.Parse(uploadUrl); err != nil {\n\treturn \"\", fmt.Errorf(\"invalid upload url %q: %v\", uploadUrl, err)\n}\nreq, err := http.NewRequest(\"POST\", uploadUrl, body)","handlingStrategy":"validation","validationCode":"host := device.GetServerPeer().Host()\nif host == \"\" {\n\treturn fmt.Errorf(\"server peer host is not configured\")\n}\nif strings.Contains(host, \"://\") {\n\treturn fmt.Errorf(\"server peer host must not include a scheme: %q\", host)\n}\nprobeUrl := \"http://\" + host + \"/\"\nif _, err := url.Parse(probeUrl + \"storage/upload\"); err != nil {\n\treturn fmt.Errorf(\"invalid upload url derived from host %q: %v\", host, err)\n}","typeGuard":"func isValidUploadHost(host string) bool {\n\tif host == \"\" || strings.Contains(host, \"://\") || strings.ContainsAny(host, \" \\t\\r\\n\") {\n\t\treturn false\n\t}\n\t_, err := url.Parse(\"http://\" + host + \"/storage/upload\")\n\treturn err == nil\n}","tryCatchPattern":"result, err := device.UploadFileToNHPServer(filePath)\nif err != nil && strings.Contains(err.Error(), \"could not create request\") {\n\treturn fmt.Errorf(\"check server peer Host in config (got %q): %w\", device.GetServerPeer().Host(), err)\n}","preventionTips":["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"],"tags":["go","http","url","config"],"backgroundTag":"invalid-url","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"}