{"record":{"id":"4ff0cc4d691f827b","repo":"VictoriaMetrics/VictoriaMetrics","slug":"cannot-parse-iat-field-w","errorCode":null,"errorMessage":"cannot parse `iat` field: %w","messagePattern":"cannot parse `iat` field: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/jwt/jwt.go","lineNumber":150,"sourceCode":"\t}\n\tb.p = parserPool.Get()\n\tjv, err := b.p.ParseBytes(b.buf)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif jv.Type() != fastjson.TypeObject {\n\t\treturn fmt.Errorf(\"unexpected non json object; type: %q\", jv.Type())\n\t}\n\tif expObject := jv.Get(\"exp\"); expObject != nil {\n\t\tb.Exp, err = expObject.Int64()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot parse `exp` field: %w\", err)\n\t\t}\n\t}\n\tif iatObject := jv.Get(\"iat\"); iatObject != nil {\n\t\tb.Iat, err = iatObject.Int64()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot parse `iat` field: %w\", err)\n\t\t}\n\t}\n\tif issObject := jv.Get(\"iss\"); issObject != nil {\n\t\tbIss, err := issObject.StringBytes()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot parse `iss` field: %w\", err)\n\t\t}\n\t\tb.Iss = bytesutil.ToUnsafeString(bIss)\n\t}\n\n\tvaObject := jv.Get(\"vm_access\")\n\tswitch {\n\tcase vaObject == nil || vaObject.Type() == fastjson.TypeNull:\n\t\tb.hasVMAccess = false\n\tdefault:\n\t\t// some IDPs encode custom claims as a string\n\t\t// try parsing as an object and fallback to a string\n\t\tswitch vaObject.Type() {","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/VictoriaMetrics/VictoriaMetrics/blob/5079fb58f1e8e62113f90c945ad71586c797d770/lib/jwt/jwt.go#L132-L168","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: iat as RFC3339 string\n{ \"iat\": \"2024-01-01T00:00:00Z\" }\n// after: iat as Unix seconds number\n{ \"iat\": 1704067200 }","handlingStrategy":"validation","validationCode":"func iatIsNumeric(seg string) bool {\n\tb, _ := base64.RawURLEncoding.DecodeString(strings.TrimRight(seg, \"=\"))\n\tvar v struct{ Iat any `json:\"iat\"` }\n\tif json.Unmarshal(b, &v) != nil { return false }\n\t_, ok := v.Iat.(float64)\n\treturn ok\n}","typeGuard":"func isNumericDate(v any) bool {\n\t_, ok := v.(float64)\n\treturn ok\n}","tryCatchPattern":"if err := t.Parse(src, enforcePrefix); err != nil {\n\tif strings.Contains(err.Error(), \"cannot parse `iat` field\") {\n\t\t// reject token: iat is not a NumericDate\n\t}\n\treturn err\n}","preventionTips":["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."],"tags":["jwt","json","timestamp"],"backgroundTag":"jwt-malformed-token","analyzedSha":"5079fb58f1e8e62113f90c945ad71586c797d770","analyzedAt":"2026-09-03T18:10:26.153Z","contentChangedAt":"2026-09-03T18:10:26.153Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}