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

  1. Print/validate the final uploadUrl (httpHost + "storage/upload") with url.Parse and inspect the wrapped error for the exact parse failure
  2. Fix the server peer Host value in the daemon's configuration so it is a bare host[:port] without scheme, spaces, or control characters
  3. Guard before calling: skip or fail fast if a.GetServerPeer().Host() is empty or fails url.Parse
  4. 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

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)