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
- Verify the target URL is reachable: curl -I <url> from the same machine
- Check DNS resolution (nslookup/dig) for the hostname
- Confirm network/firewall/proxy settings allow outbound HTTPS to the host
- Investigate intermittent slowness if the wrapped error is a timeout — the client uses a 7-second timeout
- 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
- Pre-check DNS and TCP reachability of the Access app host
- Account for the 7-second client timeout; avoid using it on slow hosts
- Verify VPN/proxy settings allow egress to the target domain
- Add bounded retries with backoff for transient network errors
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
- failed to fetch JWKS from %s
- failed to get app token
- Failed to fetch resource
- quick tunnel provisioning failed with status %d: %s
- quick tunnel provisioning failed: %s
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/e13283c6936189e0.
Report an issue: GitHub.