hashicorp/nomad · error

failed to extract claims from token: %w

Error message

failed to extract claims from token: %w

What it means

This error is returned by node_identity_endpoint.Get when the signed JWT parsed successfully but its claims could not be unmarshaled into a map. It calls UnsafeClaimsWithoutVerification, which decodes the payload without signature verification; failure means the payload JSON cannot be unmarshaled into map[string]any.

Source

Thrown at client/node_identity_endpoint.go:53

	// be called before it has a JWT identity. Check we do not get an empty
	// string before attempting to parse the token.
	if identityToken == "" {
		return errors.New("node does not have a JWT identity token")
	}

	// Parse the signed JWT token from the node identity and extract the claims
	// into a map. This is done to avoid exposing the key material of the signed
	// JWT token, but still results in all the claims which is perfect for
	// debugging and introspection purposes.
	parsedJWT, err := jwt.ParseSigned(identityToken)
	if err != nil {
		return fmt.Errorf("failed to parsed signed token: %w", err)
	}

	claims := make(map[string]any)

	if err := parsedJWT.UnsafeClaimsWithoutVerification(&claims); err != nil {
		return fmt.Errorf("failed to extract claims from token: %w", err)
	}

	resp.Claims = claims
	return nil
}

func (n *NodeIdentity) Renew(args *structs.NodeIdentityRenewReq, _ *structs.NodeIdentityRenewResp) error {

	// Check node write permissions.
	if aclObj, err := n.c.ResolveToken(args.AuthToken); err != nil {
		return err
	} else if !aclObj.AllowNodeWrite() {
		return structs.ErrPermissionDenied
	}

	// Store the node identity renewal request on the client, so it can be
	// picked up at the next heartbeat.
	n.c.identityForceRenewal.Store(true)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Regenerate the node identity token by restarting the Nomad client agent so the server issues a fresh, well-formed JWT
  2. Base64-decode the payload segment and confirm it is a JSON object with claim keys
  3. Ensure the token file contains a Nomad-issued identity token, not an arbitrary or foreign token
  4. Check Nomad agent/server version compatibility; older agents should not be fed tokens from newer formats

Example fix

// before: trusting any token file content
claims := make(map[string]any)
if err := parsedJWT.UnsafeClaimsWithoutVerification(&claims); err != nil {
    return fmt.Errorf("failed to extract claims from token: %w", err)
}

// after: validate payload is a JSON object before decoding
payload, _ := parsedJWT.Payload()
var probe map[string]any
if err := json.Unmarshal(payload, &probe); err != nil {
    return fmt.Errorf("identity token payload is not a JSON object; regenerate node identity token: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

payloadB64 := strings.Split(strings.TrimSpace(string(tokenBytes)), ".")[1]
payload, err := base64.RawURLEncoding.DecodeString(payloadB64)
if err != nil {
	return fmt.Errorf("identity token payload not base64url: %w", err)
}
var probe map[string]any
if err := json.Unmarshal(payload, &probe); err != nil {
	return fmt.Errorf("identity token payload is not a JSON object: %w", err)
}

Type guard

func isJWTObjectPayload(token string) bool {
	parts := strings.Split(token, ".")
	if len(parts) != 3 {
		return false
	}
	payload, err := base64.RawURLEncoding.DecodeString(parts[1])
	if err != nil {
		return false
	}
	var m map[string]any
	return json.Unmarshal(payload, &m) == nil
}

Try / catch

claims, err := nodeIdentityEndpoint.Get(ctx)
if err != nil {
	if strings.Contains(err.Error(), "failed to extract claims") {
		// token payload not a JSON object: regenerate via agent restart
		return regenerateAndRetry(ctx)
	}
	return err
}

Prevention

When it happens

Trigger: Calling the node identity RPC/endpoint when the JWT payload segment is not valid JSON, is not a JSON object (e.g. an array or string), or contains claims that cannot unmarshal into a map.

Common situations: A hand-crafted or corrupted token where the payload is not a JSON object; an opaque token issued by a non-Nomad identity provider placed in the token file; truncated base64 payload that decodes to invalid JSON.

Related errors


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