hashicorp/nomad · error

Failed to parse X-Nomad-LastContact: %v

Error message

Failed to parse X-Nomad-LastContact: %v

What it means

The Nomad API client parses the X-Nomad-LastContact response header as a uint64 millisecond duration when decoding query metadata (parseQueryMeta). If the header is missing, empty, or not a valid unsigned integer, strconv.ParseUint fails and this error wraps the underlying parse error. It indicates the server response (or an intermediate proxy) did not supply a well-formed LastContact header.

Source

Thrown at api/api.go:1194

	}
	return wm, nil
}

// parseQueryMeta is used to help parse query meta-data
func parseQueryMeta(resp *http.Response, q *QueryMeta) error {
	header := resp.Header

	// Parse the X-Nomad-Index
	index, err := strconv.ParseUint(header.Get("X-Nomad-Index"), 10, 64)
	if err != nil {
		return fmt.Errorf("Failed to parse X-Nomad-Index: %v", err)
	}
	q.LastIndex = index

	// Parse the X-Nomad-LastContact
	last, err := strconv.ParseUint(header.Get("X-Nomad-LastContact"), 10, 64)
	if err != nil {
		return fmt.Errorf("Failed to parse X-Nomad-LastContact: %v", err)
	}
	if last > math.MaxInt64 {
		return fmt.Errorf("Last contact duration is out of range: %d", last)
	}
	q.LastContact = time.Duration(last) * time.Millisecond
	q.NextToken = header.Get("X-Nomad-NextToken")

	// Parse the X-Nomad-KnownLeader
	switch header.Get("X-Nomad-KnownLeader") {
	case "true":
		q.KnownLeader = true
	default:
		q.KnownLeader = false
	}
	return nil
}

// parseWriteMeta is used to help parse write meta-data

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check what server actually responded: curl -v the endpoint and inspect the X-Nomad-LastContact header
  2. Remove or fix proxy/load-balancer config that strips X-Nomad-* headers
  3. Verify the client is pointed at a real Nomad agent HTTP endpoint (default port 4646)
  4. Upgrade the Nomad agent/client if versions are mismatched

Example fix

// before
c.Error = httpResp.Header.Get("X-Nomad-LastContact") // empty through proxy
// after
proxy_pass_headers X-Nomad-LastContact; // nginx: forward X-Nomad-* headers
Defensive patterns

Strategy: validation

Validate before calling

resp, _ := http.Get(url)
if v := resp.Header.Get("X-Nomad-LastContact"); v == "" {
    if _, err := strconv.ParseUint(v, 10, 64); err != nil {
        return fmt.Errorf("server did not return a valid X-Nomad-LastContact header")
    }
}

Type guard

func hasValidLastContact(h http.Header) bool {
    _, err := strconv.ParseUint(h.Get("X-Nomad-LastContact"), 10, 64)
    return err == nil
}

Prevention

When it happens

Trigger: Calling any blocking-query API method (e.g. jobs.List, nodes.List, QueryOptions-based calls) when the X-Nomad-LastContact header is absent, empty, or non-numeric — typically from a proxy/gateway stripping headers or a non-Nomad server responding.

Common situations: Requests routed through reverse proxies or load balancers that drop X-Nomad-* headers; pointing the client at a non-Nomad HTTP endpoint; intercepted/mocked responses in tests lacking the header.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/6a3a457f6d62d649. Report an issue: GitHub.