VictoriaMetrics/VictoriaMetrics · error
cannot parse `iat` field: %w
Error message
cannot parse `iat` field: %w
What it means
Fires in the fastjson-based JWT claims parser when the optional 'iat' (issued-at) claim is present but not a valid integer. Input at fault is the iat field of the JWT payload; the token is structurally invalid and will be rejected.
Source
Thrown at lib/jwt/jwt.go:150
}
b.p = parserPool.Get()
jv, err := b.p.ParseBytes(b.buf)
if err != nil {
return err
}
if jv.Type() != fastjson.TypeObject {
return fmt.Errorf("unexpected non json object; type: %q", jv.Type())
}
if expObject := jv.Get("exp"); expObject != nil {
b.Exp, err = expObject.Int64()
if err != nil {
return fmt.Errorf("cannot parse `exp` field: %w", err)
}
}
if iatObject := jv.Get("iat"); iatObject != nil {
b.Iat, err = iatObject.Int64()
if err != nil {
return fmt.Errorf("cannot parse `iat` field: %w", err)
}
}
if issObject := jv.Get("iss"); issObject != nil {
bIss, err := issObject.StringBytes()
if err != nil {
return fmt.Errorf("cannot parse `iss` field: %w", err)
}
b.Iss = bytesutil.ToUnsafeString(bIss)
}
vaObject := jv.Get("vm_access")
switch {
case vaObject == nil || vaObject.Type() == fastjson.TypeNull:
b.hasVMAccess = false
default:
// some IDPs encode custom claims as a string
// try parsing as an object and fallback to a string
switch vaObject.Type() {View on GitHub (pinned to 5079fb58f1)
Solutions
- Re-mint the token with `iat` as a JSON number of Unix seconds: {"iat": 1700000000}.
- Fix IDP claim transformation so iat is not stringified or date-formatted.
- Pre-validate the payload: decode the middle segment, check that iat is a number, and reject the token before Parse.
- Omit iat entirely if your token format doesn't need it — the parser only errors when the field exists.
Example fix
// before: iat as RFC3339 string
{ "iat": "2024-01-01T00:00:00Z" }
// after: iat as Unix seconds number
{ "iat": 1704067200 } Defensive patterns
Strategy: validation
Validate before calling
func iatIsNumeric(seg string) bool {
b, _ := base64.RawURLEncoding.DecodeString(strings.TrimRight(seg, "="))
var v struct{ Iat any `json:"iat"` }
if json.Unmarshal(b, &v) != nil { return false }
_, ok := v.Iat.(float64)
return ok
} Type guard
func isNumericDate(v any) bool {
_, ok := v.(float64)
return ok
} Try / catch
if err := t.Parse(src, enforcePrefix); err != nil {
if strings.Contains(err.Error(), "cannot parse `iat` field") {
// reject token: iat is not a NumericDate
}
return err
} Prevention
- Emit iat as Unix-seconds number; avoid marshaling time.Time directly into the claim.
- Keep iat absent if unused — the parser only validates it when present.
- Add a CI check that decodes a sample token and asserts claim types.
- Review IDP claim-mapping transforms after upgrades.
When it happens
Trigger: Parsing a token whose payload contains e.g. "iat":"2024-01-01T00:00:00Z", "iat":1700000000.5 is fine but "iat":"1700000000" (string) or "iat":{} is not.
Common situations: IDPs with claim mappings that serialize iat as an ISO-8601 string; custom token generators using time.Time marshaled to RFC3339; hand-rolled test fixtures.
Related errors
- cannot parse `exp` field: %w
- unexpected empty json
- unexpected non json object {} type: %q
- unexpected non json object; type: %q
- cannot parse `iss` field: %w
AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03).
Data as JSON: /api/errors/4ff0cc4d691f827b.
Report an issue: GitHub.