{"record":{"id":"a6bd2e4f62b0ff2a","repo":"grpc/grpc-go","slug":"rls-failed-to-parse-max-age-in-route-lookup-confi","errorCode":null,"errorMessage":"rls: failed to parse max_age in route lookup config %+v: %v","messagePattern":"rls: failed to parse max_age in route lookup config %\\+v: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/rls/config.go","lineNumber":229,"sourceCode":"\t}\n\n\tlookupServiceTimeout, err := convertDuration(rlsProto.GetLookupServiceTimeout())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"rls: failed to parse lookup_service_timeout in route lookup config %+v: %v\", rlsProto, err)\n\t}\n\tif lookupServiceTimeout == 0 {\n\t\tlookupServiceTimeout = defaultLookupServiceTimeout\n\t}\n\n\t// Validations performed here:\n\t// - if `max_age` > 5m, it should be set to 5 minutes\n\t//   only if stale age is not set\n\t// - if `stale_age` > `max_age`, ignore it\n\t// - if `stale_age` is set, then `max_age` must also be set\n\tmaxAgeSet := false\n\tmaxAge, err := convertDuration(rlsProto.GetMaxAge())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"rls: failed to parse max_age in route lookup config %+v: %v\", rlsProto, err)\n\t}\n\tif maxAge == 0 {\n\t\tmaxAge = maxMaxAge\n\t} else {\n\t\tmaxAgeSet = true\n\t}\n\n\tstaleAgeSet := false\n\tstaleAge, err := convertDuration(rlsProto.GetStaleAge())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"rls: failed to parse staleAge in route lookup config %+v: %v\", rlsProto, err)\n\t}\n\tif staleAge == 0 {\n\t\tstaleAge = maxMaxAge\n\t} else {\n\t\tstaleAgeSet = true\n\t}\n","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/rls/config.go#L211-L247","documentation":"Returned by parseRLSProto (config.go:227-230) when convertDuration fails on RouteLookupConfig.max_age for the same reason as the timeout: the google.protobuf.Duration is out of range (durationpb.CheckValid rejects invalid seconds/nanos). Note valid values are capped to 5 minutes (maxMaxAge) after parsing.","triggerScenarios":"max_age Duration proto is structurally invalid (out-of-range seconds or nanos). A value of 0 is valid (defaults to 5m); only structurally invalid Durations trigger this.","commonSituations":"Control-plane overflow building the Duration. Manually setting Nanos out of [-1e9,1e9).","solutions":["Provide a sane max_age (0 to use the 5-minute default, or <= 5m); the policy caps it at 5 minutes anyway.","Build the Duration with durationpb.New(time.Duration) to guarantee validity.","Check the control plane's max_age generation."],"exampleFix":"// before\nrlc.MaxAge = &durationpb.Duration{ Seconds: -1, Nanos: -1000000000 } // invalid nanos\n\n// after\nrlc.MaxAge = durationpb.New(5 * time.Minute)","handlingStrategy":"validation","validationCode":"func validateMaxAge(d *durationpb.Duration) error {\n    if d == nil { return nil }\n    return d.CheckValid()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use durationpb.New to build max_age (capped at 5m anyway).","0 means use the 5m default; only structurally invalid values fail."],"tags":["go","grpc","load-balancing","rls","config","duration","protobuf"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}