thanos-io/thanos · error · api.ApiError
negative ' ' is not accepted. Try a positive integer
Error message
negative '%s' is not accepted. Try a positive integer
What it means
After successfully parsing max_source_resolution, parseDownsamplingParamMillis rejects negative durations with a dedicated ErrorBadData message "negative 'max_source_resolution' is not accepted. Try a positive integer". A negative resolution is meaningless for downsampling, so it is explicitly refused.
Solutions
- Clamp the value to a positive duration (or zero/auto) in the client before sending
- Fix the sign of the computed expression producing the negative value
- Add client-side validation: reject values starting with '-' or parse and check < 0
- Use 'auto' instead of a computed value when unsure
Example fix
// before res="-$interval" # -5m // after res="$interval" # 5m; or Math.max(0, parsed) in tooling
Defensive patterns
Strategy: validation
Validate before calling
function validatePositiveDuration(v) {
if (typeof v === 'string' && (v === 'auto' || !v.startsWith('-'))) return v;
const ms = parsePromDurationToMs(v);
if (ms < 0) throw new Error('max_source_resolution must be positive');
return v;
} Type guard
null
Try / catch
try {
const res = await fetch(url);
const j = await res.json();
if (j.status === 'error' && /negative.*max_source_resolution/.test(j.error)) throw new Error(j.error);
} catch (e) {
if (/negative.*max_source_resolution/.test(e.message)) { /* clamp to 0 or 'auto' and retry */ }
throw e;
} Prevention
- Clamp computed intervals to >= 0 before use
- Check sign when doing interval arithmetic in scripts/shell
- Add assertions in dashboard variable expressions
- Treat 0/auto as the safe fallback
When it happens
Trigger: Passing max_source_resolution=-5m, -1h, or any negative duration on query/query_range or explain endpoints, typically from templated dashboards or arithmetic in scripts producing negative values.
Common situations: Grafana variables computed from interval math going negative; shell scripts doing $(($a - $b)) with reversed operands; copying a step value that was negated.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/0bbf42496e4a84b3.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/query/v1.go:383
}
func (qapi *QueryAPI) parseDownsamplingParamMillis(r *http.Request, defaultVal time.Duration) (maxResolutionMillis int64, _ *api.ApiError) {
maxSourceResolution := 0 * time.Second
val := r.FormValue(MaxSourceResolutionParam)
if qapi.enableAutodownsampling || (val == "auto") {
maxSourceResolution = defaultVal
}
if val != "" && val != "auto" {
var err error
maxSourceResolution, err = parseDuration(val)
if err != nil {
return 0, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Wrapf(err, "'%s' parameter", MaxSourceResolutionParam)}
}
}
if maxSourceResolution < 0 {
return 0, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("negative '%s' is not accepted. Try a positive integer", MaxSourceResolutionParam)}
}
return int64(maxSourceResolution / time.Millisecond), nil
}
func (qapi *QueryAPI) parsePartialResponseParam(r *http.Request, defaultEnablePartialResponse bool) (enablePartialResponse bool, _ *api.ApiError) {
// Overwrite the cli flag when provided as a query parameter.
if val := r.FormValue(PartialResponseParam); val != "" {
var err error
defaultEnablePartialResponse, err = strconv.ParseBool(val)
if err != nil {
return false, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Wrapf(err, "'%s' parameter", PartialResponseParam)}
}
}
return defaultEnablePartialResponse, nil
}
func (qapi *QueryAPI) parseStep(r *http.Request, defaultRangeQueryStep time.Duration, rangeSeconds int64) (time.Duration, *api.ApiError) {View on GitHub (pinned to 35b8b99117)