{"record":{"id":"be073f10108fe10a","repo":"thanos-io/thanos","slug":"invalid-duration","errorCode":null,"errorMessage":"invalid duration","messagePattern":"invalid duration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cortex/querier/queryrange/query_range.go","lineNumber":955,"sourceCode":"\nfunc (d *Duration) UnmarshalJSON(b []byte) error {\n\tvar v any\n\tif err := json.Unmarshal(b, &v); err != nil {\n\t\treturn err\n\t}\n\tswitch value := v.(type) {\n\tcase float64:\n\t\t*d = Duration(time.Duration(value))\n\t\treturn nil\n\tcase string:\n\t\ttmp, err := time.ParseDuration(value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*d = Duration(tmp)\n\t\treturn nil\n\tdefault:\n\t\treturn errors.New(\"invalid duration\")\n\t}\n}\n\nfunc (d *Duration) Size() int {\n\treturn github_com_gogo_protobuf_types.SizeOfStdDuration(time.Duration(*d))\n}\n\nfunc (d *Duration) Unmarshal(b []byte) error {\n\tvar td time.Duration\n\tif err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&td, b); err != nil {\n\t\treturn err\n\t}\n\t*d = Duration(td)\n\treturn nil\n}\n\nfunc (d *Duration) MarshalTo(b []byte) (int, error) {\n\treturn github_com_gogo_protobuf_types.StdDurationMarshalTo(time.Duration(*d), b)","sourceCodeStart":937,"sourceCodeEnd":973,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/internal/cortex/querier/queryrange/query_range.go#L937-L973","documentation":"Thrown by the Unmarshal method of queryrange.Duration (a gogo-protobuf generated wrapper around time.Duration) when the incoming value is neither a number/protobuf duration nor a valid string form. The decoder falls into the `default` branch of a type switch, meaning the JSON/YAML field holding a duration had an unrecognized type (e.g. an object, bool, or malformed scalar).","triggerScenarios":"Deserializing a query-range request or config where a duration field (step, interval, timeout) is supplied as a non-numeric, non-string JSON value — e.g. `\"step\": true`, `\"step\": {}`, or a string protobuf cannot parse as a duration.","commonSituations":"Hand-written JSON bodies posted to the query-frontend API; templated configs where a duration placeholder renders as a wrong type; clients sending step as a bare word like `step` instead of `\"1m\"`.","solutions":["Send the duration as a numeric nanosecond value or a quoted string like \"1m\"/\"500ms\"","Check the JSON payload's Content-Type and body for type errors in duration fields","Update the client SDK/serializer to emit protobuf-compatible duration encodings"],"exampleFix":"// before\n{\"query\":\"up\",\"step\":five-minutes}\n// after\n{\"query\":\"up\",\"step\":\"5m\"}","handlingStrategy":"validation","validationCode":"func validDuration(v interface{}) bool {\n\tswitch t := v.(type) {\n\tcase float64:\n\t\treturn t >= 0\n\tcase string:\n\t\t_, err := time.ParseDuration(t)\n\t\treturn err == nil\n\t}\n\treturn false\n}","typeGuard":"if d, ok := raw.(string); !ok { return errors.New(\"duration must be string\") }","tryCatchPattern":"if err := json.Unmarshal(body, &req); err != nil {\n\tif strings.Contains(err.Error(), \"invalid duration\") {\n\t\treturn http.StatusBadRequest(\"duration fields must be numeric ns or quoted like \\\"5m\\\"\")\n\t}\n}","preventionTips":["Always serialize durations as strings (\"1m\", \"500ms\") or nanosecond numbers","Add schema validation (JSON schema/OpenAPI) on duration fields before sending","Test client payloads against the API's duration decoder"],"tags":["deserialization","duration","protobuf","cortex"],"backgroundTag":"invalid-duration-format","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}