OpenNHP/opennhp · error

could not send https request

Error message

could not send https request: %v

What it means

The function sends the prepared POST with client.Do(req) using an http.Client with a 120-minute timeout. Any transport-level failure — DNS resolution, TCP connect, TLS handshake, connection reset, or timeout — is wrapped as "could not send https request: %v" with the Go net/http error verbatim. This is a client-side network failure, not an HTTP error status.

Solutions

  1. Read the wrapped error: "connection refused" → check the server process and port; "no such host" → fix DNS; "x509" → fix or trust the server certificate (or configure TLS properly rather than disabling verification)
  2. Verify the NHP-DB server's HTTP endpoint is up and reachable: curl the httpHost probe URL used at utils.go:195 from the same machine
  3. Correct the server Host in the peer configuration (host/IP and port) so the probe and upload URLs point at the right listener
  4. If uploads are large and links are slow, confirm the 120-minute timeout is sufficient or raise it; for transient network errors, add bounded retry with backoff around the upload

Example fix

// before
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)
}
// after
client := &http.Client{
	Timeout: 120 * time.Minute,
	Transport: &http.Transport{
		TLSClientConfig: &tls.Config{RootCAs: trustedPool}, // trust the NHP server CA
	},
}
var resp *http.Response
var lastErr error
for attempt := 0; attempt < 3; attempt++ {
	resp, lastErr = client.Do(req)
	if lastErr == nil {
		break
	}
	time.Sleep(time.Duration(attempt+1) * 2 * time.Second) // retry transient network failures
}
if lastErr != nil {
	return "", fmt.Errorf("could not send https request: %v", lastErr)
}
Defensive patterns

Strategy: retry

Validate before calling

host := device.GetServerPeer().Host()
probeUrl := "http://" + host + "/"
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Get(probeUrl)
if err != nil {
	return fmt.Errorf("NHP server %s unreachable before upload: %v", host, err)
}
resp.Body.Close()

Type guard

func serverReachable(host string) bool {
	c := &http.Client{Timeout: 10 * time.Second}
	resp, err := c.Get("http://" + host + "/")
	if err != nil {
		return false
	}
	resp.Body.Close()
	return true
}

Try / catch

result, err := device.UploadFileToNHPServer(filePath)
if err != nil && strings.Contains(err.Error(), "could not send https request") {
	if strings.Contains(err.Error(), "x509") {
		// TLS trust problem: install/trust the server CA
	} else if errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), "timeout") {
		// retry with backoff or increase timeout
	}
	return fmt.Errorf("network failure uploading to NHP server: %w", err)
}

Prevention

When it happens

Trigger: client.Do fails in UploadFileToNHPServer (endpoints/db/utils.go:258-261): server unreachable (connection refused), DNS failure for the configured host, TLS certificate errors when the https fallback (utils.go:201) is used against a server with a self-signed/untrusted cert, request taking longer than the 120s… er, 120-minute client.Timeout, or network interruption mid-upload of a large body.

Common situations: NHP-DB server down or wrong port in the peer configuration; firewall blocking the HTTP(S) port; https fallback against a demo server with a self-signed certificate yielding "x509: certificate signed by unknown authority"; uploading huge files over a flaky VPN link; DNS not resolving the server hostname.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/061756ba671ddfe2. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/db/utils.go:260

		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))
	}

	// 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

View on GitHub (pinned to 6e04ca5ff0)