OpenNHP/opennhp · error

failed to download ztdo

Error message

failed to download ztdo: %v

What it means

The agent failed to download the ztdo file from dagMsg.AccessUrl via utils.DownloadFileToTemp. The underlying error (DNS failure, HTTP error status, TLS problem, disk write failure) is wrapped verbatim. This is a network/IO error on the client side while fetching the provider-hosted payload.

Solutions

  1. Inspect the wrapped inner error to identify whether it is DNS, HTTP status, TLS, or disk IO.
  2. Test the AccessUrl directly with curl from the agent host to reproduce.
  3. Re-request the ztdo to get a fresh (non-expired) URL from the provider.
  4. Ensure the provider's storage endpoint is publicly reachable or on a network path reachable by the agent.
  5. Check local temp directory permissions and free disk space.

Example fix

// before: opaque wrap only
if err != nil {
    return "", fmt.Errorf("failed to download ztdo: %v", err)
}

// after: retry once before giving up
var ztdoPath string
var err error
for i := 0; i < 2; i++ {
    ztdoPath, err = utils.DownloadFileToTemp(dagMsg.AccessUrl, "ztdo-")
    if err == nil {
        break
    }
    time.Sleep(2 * time.Second)
}
if err != nil {
    return "", fmt.Errorf("failed to download ztdo: %v", err)
}
Defensive patterns

Strategy: retry

Validate before calling

u, err := url.Parse(dagMsg.AccessUrl)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("malformed access url: %q", dagMsg.AccessUrl)
}

Type guard

func isDownloadable(u string) bool { p, err := url.Parse(u); return err == nil && (p.Scheme == "https" || p.Scheme == "http") && p.Host != "" }

Try / catch

var ztdoPath string
var err error
for attempt := 0; attempt < 3; attempt++ {
    ztdoPath, err = utils.DownloadFileToTemp(accessUrl, "ztdo-")
    if err == nil { break }
    time.Sleep(time.Duration(attempt+1) * time.Second)
}

Prevention

When it happens

Trigger: utils.DownloadFileToTemp(dagMsg.AccessUrl, "ztdo-") returns a non-nil error: unreachable host, 404/403 from object storage, expired pre-signed URL, TLS cert issues, or local temp-dir write failure.

Common situations: Expired or rotated pre-signed S3 URLs; data provider host behind firewall not reachable from the agent network; DNS misconfiguration; provider URL points to localhost/internal address; disk full on the agent host.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at endpoints/agent/udpagent.go:1374

			dataPrkWrapping := ztdolib.DataPrivateKeyWrapping{}

			if err := json.Unmarshal([]byte(dagMsg.Kao.WrappedDataKey), &dataPrkWrapping); err != nil {
				log.Error("failed to unmarshal data private key wrapping: %v\n", err)
				return "", fmt.Errorf("failed to unmarshal data private key wrapping: %v", err)
			}

			providerPbk, _ := base64.StdEncoding.DecodeString(dataPrkWrapping.ProviderPublicKeyBase64)

			if dagMsg.AccessUrl == "" {
				log.Error("access url is empty, please check with data provider")
				return "", fmt.Errorf("access url is empty, please check with data provider")
			}

			var err error
			ztdoPath, err := utils.DownloadFileToTemp(dagMsg.AccessUrl, "ztdo-")
			if err != nil {
				log.Error("failed to download ztdo: %v\n", err)
				return "", fmt.Errorf("failed to download ztdo: %v", err)
			}

			if parseErr := ztdo.ParseHeader(ztdoPath); parseErr != nil {
				fmt.Printf("Error: failed to parse ztdo header:%s\n", parseErr)
				return "", fmt.Errorf("failed to parse ztdo header:%s", parseErr)
			}

			if ztdoId != ztdo.GetObjectID() {
				fmt.Printf("Error: ztdo id mismatch, please check with data provider\n")
				return "", fmt.Errorf("ztdo id mismatch, please check with data provider")
			}

			// decrypt data private key
			saDataPrk := ztdolib.NewSymmetricAgreement(ztdo.GetECCMode(), false)
			saDataPrk.SetMessagePatterns(ztdolib.DataPrivateKeyWrappingPatterns)
			saDataPrk.SetPsk([]byte(ztdolib.InitialDHPKeyWrappingString))
			saDataPrk.SetStaticKeyPair(teeEcdh)
			saDataPrk.SetEphemeralKeyPair(consumerEphemeralEcdh)

View on GitHub (pinned to 6e04ca5ff0)