thanos-io/thanos · error
unmarshaling scalar time from
Error message
unmarshaling scalar time from %v
What it means
The first element of the scalar tuple must decode into prometheus/common's model.Time (a millisecond Unix timestamp number). This error wraps json.Unmarshal failing on resultPointSlice[0] — the timestamp element is not a number (e.g. a string, null, or object).
Solutions
- Ensure the server emits the timestamp as a JSON number in Unix milliseconds.
- Log resultPointSlice[0] to see the offending value.
- Fix test fixtures to use numeric epoch-millisecond timestamps.
- If the upstream genuinely sends string timestamps, convert on the server side rather than patching the client.
Example fix
// before "result": ["2024-03-09T12:00:00Z", "42"] // after "result": [1710000000000, "42"]
Defensive patterns
Strategy: validation
Validate before calling
// fixture check: tuple[0] must be a JSON number (unix ms)
var ts json.Number
if err := json.Unmarshal(raw[0], &ts); err != nil {
return fmt.Errorf("scalar timestamp must be numeric unix ms, got %s", raw[0])
} Try / catch
if err != nil && strings.Contains(err.Error(), "unmarshaling scalar time") {
// timestamp element wrong type; log it and fix the source
} Prevention
- Emit timestamps as epoch milliseconds, never ISO strings or null
- Generate test fixtures from real Prometheus responses
- Check server implementation for custom timestamp formatting
When it happens
Trigger: QueryInstant/TestRule_UnmarshalScalarResponse receives a scalar result whose tuple[0] is not JSON-parseable into model.Time: string timestamps, null, or nested values.
Common situations: Custom or buggy server emitting timestamps as ISO strings instead of epoch milliseconds; hand-written test fixtures with wrong types; middleware converting numbers to strings.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- unmarshaling scalar value from
- unmarshal response
- unmarshal query instant response
- decode result into ValueTypeScalar
- unmarshal query range response
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/d6d759dbd5c116b0.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/promclient/promclient.go:621
// Scalar response consists of array with mixed types so it needs to be
// unmarshaled separately.
func convertScalarJSONToVector(scalarJSONResult json.RawMessage) (model.Vector, error) {
var (
// Do not specify exact length of the expected slice since JSON unmarshaling
// would make the length fit the size and we won't be able to check the length afterwards.
resultPointSlice []json.RawMessage
resultTime model.Time
resultValue model.SampleValue
)
if err := json.Unmarshal(scalarJSONResult, &resultPointSlice); err != nil {
return nil, err
}
if len(resultPointSlice) != 2 {
return nil, errors.Errorf("invalid scalar result format %v, expected timestamp -> value tuple", resultPointSlice)
}
if err := json.Unmarshal(resultPointSlice[0], &resultTime); err != nil {
return nil, errors.Wrapf(err, "unmarshaling scalar time from %v", resultPointSlice)
}
if err := json.Unmarshal(resultPointSlice[1], &resultValue); err != nil {
return nil, errors.Wrapf(err, "unmarshaling scalar value from %v", resultPointSlice)
}
return model.Vector{&model.Sample{
Metric: model.Metric{},
Value: resultValue,
Timestamp: resultTime}}, nil
}
// AlertmanagerAlerts returns alerts from Alertmanager.
func (c *Client) AlertmanagerAlerts(ctx context.Context, base *url.URL) ([]*model.Alert, error) {
u := *base
u.Path = path.Join(u.Path, "/api/v1/alerts")
level.Debug(c.logger).Log("msg", "querying instant", "url", u.String())
span, ctx := tracing.StartSpan(ctx, "/alertmanager_alerts HTTP[client]")View on GitHub (pinned to 35b8b99117)