{"record":{"id":"9e2ff5364cfb9bed","repo":"thanos-io/thanos","slug":"cannot-parse-q-to-a-valid-timestamp","errorCode":null,"errorMessage":"cannot parse %q to a valid timestamp","messagePattern":"cannot parse %q to a valid timestamp","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"pkg/api/query/v1.go","lineNumber":1599,"sourceCode":"\t\treturn defaultValue, nil\n\t}\n\tresult, err := parseTime(val)\n\tif err != nil {\n\t\treturn time.Time{}, errors.Wrapf(err, \"Invalid time value for '%s'\", paramName)\n\t}\n\treturn result, nil\n}\n\nfunc parseTime(s string) (time.Time, error) {\n\tif t, err := strconv.ParseFloat(s, 64); err == nil {\n\t\ts, ns := math.Modf(t)\n\t\tns = math.Round(ns*1000) / 1000\n\t\treturn time.Unix(int64(s), int64(ns*float64(time.Second))), nil\n\t}\n\tif t, err := time.Parse(time.RFC3339Nano, s); err == nil {\n\t\treturn t, nil\n\t}\n\treturn time.Time{}, errors.Errorf(\"cannot parse %q to a valid timestamp\", s)\n}\n\nfunc parseDuration(s string) (time.Duration, error) {\n\tif d, err := strconv.ParseFloat(s, 64); err == nil {\n\t\tts := d * float64(time.Second)\n\t\tif ts > float64(math.MaxInt64) || ts < float64(math.MinInt64) {\n\t\t\treturn 0, errors.Errorf(\"cannot parse %q to a valid duration. It overflows int64\", s)\n\t\t}\n\t\treturn time.Duration(ts), nil\n\t}\n\tif d, err := model.ParseDuration(s); err == nil {\n\t\treturn time.Duration(d), nil\n\t}\n\treturn 0, errors.Errorf(\"cannot parse %q to a valid duration\", s)\n}\n\n// parseLimitParam returning 0 means no limit is to be applied.\nfunc parseLimitParam(s string) (int, error) {","sourceCodeStart":1581,"sourceCodeEnd":1617,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/api/query/v1.go#L1581-L1617","documentation":"The terminal error of parseTime: when the string is neither a parseable unix float nor a valid RFC3339Nano timestamp, this error is returned (and often wrapped by 'Invalid time value for %s' upstream). It is an ErrorBadData (HTTP 400) indicating the timestamp format is unrecognized.","triggerScenarios":"Any time parameter receiving a string that fails strconv.ParseFloat and time.Parse(RFC3339Nano), e.g. 'time=2024-01-02' (date only, no time/zone) or 'time=1704153600000' passed as float is fine, but 'time=xyz' fails both paths.","commonSituations":"Date-only strings without T/Z suffix, epoch milliseconds as an integer string (parses as float seconds — yields a far-future time rather than this error, a subtle bug), locale-formatted datetimes, or empty-ish garbage values that slipped past empty checks.","solutions":["Format the value as RFC3339Nano (e.g. 2024-01-02T15:04:05.999999999Z07:00).","Or send a unix seconds float; convert ms epochs by dividing by 1000.","URL-encode the timestamp so '+' and ':' survive transport.","Add client-side pre-validation with the same two parse rules before calling the API."],"exampleFix":"// before\nparams.set('start', '2024-01-02') // date-only, unparseable\n// after\nparams.set('start', new Date('2024-01-02').toISOString()) // RFC3339","handlingStrategy":"validation","validationCode":"const isValidApiTime = (s) => /^-?\\d+(\\.\\d+)?$/.test(s) || !Number.isNaN(Date.parse(s));\n// pre-check: if (!isValidApiTime(v)) fixBeforeRequest(v);","typeGuard":"function isParseableTimestamp(s) { return /^-?\\d+(\\.\\d+)?$/.test(s) || !Number.isNaN(Date.parse(s)); }","tryCatchPattern":null,"preventionTips":["Use toISOString()/RFC3339Nano for all timestamp params.","Never send date-only strings; include time and zone.","Keep one shared timestamp serializer for all Thanos API calls."],"tags":["api","validation","time","parsing"],"backgroundTag":"invalid-date-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"}