cloudflare/cloudflared · error

failed to get app info

Error message

failed to get app info

What it means

This error wraps a client.Do failure when issuing the HEAD request that fetches the Access application metadata JWT (via the Cf-Access-Jwt-Assertion style header) from the target URL. It is thrown when the HTTP round trip itself fails — DNS resolution, TCP connect, TLS handshake, or timeout (the client has a 7-second timeout). It is a transport-level error, not an HTTP status problem.

Source

Thrown at token/token.go:496

// followed.
func fetchMetadataJWT(reqURL string) (string, error) {
	client := &http.Client{
		CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
			return http.ErrUseLastResponse
		},
		Timeout: time.Second * 7,
	}

	req, err := http.NewRequest("HEAD", reqURL, nil)
	if err != nil {
		return "", errors.Wrap(err, "failed to create app info request")
	}
	req.Header.Set(accessMetadataReqHeader, accessMetadataReqValue)
	req.Header.Set(userAgentHeader, userAgent)

	resp, err := client.Do(req) // nolint: gosec
	if err != nil {
		return "", errors.Wrap(err, "failed to get app info")
	}
	_ = resp.Body.Close()

	rawJWT := resp.Header.Get(accessMetadataRespHeader)
	if rawJWT == "" {
		return "", fmt.Errorf("failed to find Access application at %s", reqURL)
	}
	return rawJWT, nil
}

func validateMetadataIssuedAt(iat int64, now time.Time) error {
	if iat <= 0 {
		return errors.New("metadata JWT iat is missing or invalid")
	}
	issuedAt := time.Unix(iat, 0)
	if issuedAt.Before(now.Add(-metadataMaxAge)) {
		return fmt.Errorf("metadata JWT is older than %s", metadataMaxAge)
	}

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Verify the target URL is reachable: curl -I <url> from the same machine
  2. Check DNS resolution (nslookup/dig) for the hostname
  3. Confirm network/firewall/proxy settings allow outbound HTTPS to the host
  4. Investigate intermittent slowness if the wrapped error is a timeout — the client uses a 7-second timeout
  5. Retry the operation if the failure was transient (network blip)

Example fix

// before: no reachability check
jwt, err := fetchMetadataJWT(ctx, reqURL, log)
// after: probe connectivity first
resp, err := http.Head(reqURL)
if err != nil {
	return fmt.Errorf("app at %s is unreachable, check network/DNS: %w", reqURL, err)
}
resp.Body.Close()
jwt, err = fetchMetadataJWT(ctx, reqURL, log)
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", host+":443", 3*time.Second)
if err != nil {
	return fmt.Errorf("app host unreachable before metadata fetch: %w", err)
}
conn.Close()

Try / catch

for attempt := 0; attempt < 3; attempt++ {
	jwt, err := GetAppInfo(ctx, reqURL, log)
	if err == nil {
		break
	}
	if !strings.Contains(err.Error(), "failed to get app info") {
		return err
	}
	time.Sleep(time.Duration(1<<attempt) * time.Second)
}

Prevention

When it happens

Trigger: fetchMetadataJWT (via GetAppInfo) calls client.Do(req) and receives a non-nil err: host unreachable, DNS failure, connection refused, TLS error, or the 7-second timeout elapses.

Common situations: Target host is behind a firewall or offline; no network connectivity; private/internal hostname not resolvable from the machine; TLS interception proxies breaking the handshake; server slow to respond causing the 7s timeout.

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 cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/e13283c6936189e0. Report an issue: GitHub.