jaegertracing/jaeger · error

file must begin with '['

Error message

file must begin with '['

What it means

lengthOfTime reads a constant that must represent a duration and parses it via expression.ReadConstant with FieldTypeDuration. When the constant's text is not a valid duration string (e.g. "2s", "100ms"), ReadConstant fails and the filter is rejected as invalid, wrapping tracestore.ErrFilterInvalid so callers can detect it with errors.Is. This happens when a duration comparison (e.g. duration > X) is built from a tree whose constant was not finalized into a DurationValue.

Source

Thrown at cmd/anonymizer/app/uiconv/reader.go:57

		capturedFile: cf,
		reader:       bufio.NewReader(cf),
	}, nil
}

// NextSpan reads the next span from the capture file, or returns errNoMoreSpans.
func (r *spanReader) NextSpan() (*uimodel.Span, error) {
	if r.eofReached {
		return nil, errNoMoreSpans
	}
	if r.spansRead == 0 {
		b, err := r.reader.ReadByte()
		if err != nil {
			r.eofReached = true
			return nil, fmt.Errorf("cannot read file: %w", err)
		}
		if b != '[' {
			r.eofReached = true
			return nil, errors.New("file must begin with '['")
		}
	}
	s, err := r.reader.ReadString('\n')
	if err != nil {
		r.eofReached = true
		return nil, fmt.Errorf("cannot read file: %w", err)
	}
	if s[len(s)-2] == ',' { // all but last span lines end with ,\n
		s = s[0 : len(s)-2]
	} else {
		r.eofReached = true
	}
	var span uimodel.Span
	err = json.Unmarshal([]byte(s), &span)
	if err != nil {
		r.eofReached = true
		return nil, fmt.Errorf("cannot unmarshal span: %w; %s", err, s)
	}

View on GitHub (pinned to 806f444784)

Solutions

  1. Write the duration constant as a valid Go-style duration string with a unit, e.g. "2s", "100ms", "1h".
  2. Ensure the expression tree is finalized before filtering so typed constants become expression.DurationValue instead of raw untyped constants.
  3. Check the wrapped inner error (errors.Is/As on ErrFilterInvalid) to surface the parse failure message to the end user.

Example fix

// before
{"duration": {"gt": "2sec"}}
// after
{"duration": {"gt": "2s"}}
Defensive patterns

Strategy: validation

Validate before calling

func validDuration(s string) bool {
    _, err := time.ParseDuration(s)
    return err == nil
}
// check before submitting: validDuration("2s")

Type guard

func asDuration(e expression.Expression) (*expression.DurationValue, bool) {
    d, ok := e.(*expression.DurationValue)
    return d, ok
}

Try / catch

q, err := buildFilterQuery(...)
if errors.Is(err, tracestore.ErrFilterInvalid) {
    // surface parse message to user, fix duration syntax like "2s"
}

Prevention

When it happens

Trigger: Calling a trace search whose filter compares the duration field against a constant written in an unrecognized format, e.g. duration > "two seconds" or duration >= "5" without a unit; the constant reaches lengthOfTime via buildDurationComparison without having been finalized into a DurationValue.

Common situations: Typing a duration filter without a time unit in a query UI or API request; writing durations in human phrasing ("2 seconds") instead of Go-style duration syntax; a query built programmatically without running finalization on the expression tree.

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/c463dc9e05d325c9. Report an issue: GitHub.