t8y2/dbx · error

unstable result shape for %s

Error message

unstable result shape for %s

What it means

runWorkload executes each workload item multiple times and compares every observation against the first iteration's result. If a later run returns a different shape/content ('expected != observation'), it aborts with 'unstable result shape for %s', because benchmarking a non-deterministic query would produce meaningless samples.

Source

Thrown at agents/drivers/iotdb/bench/go/main.go:168

		FetchSize:     conf.FetchSize,
		Workloads:     results,
	})
}

func runWorkload(session *client.Session, conf config, item workload) (workloadResult, error) {
	samples := make([]float64, 0, item.Iterations)
	var expected queryObservation
	for index := 0; index < item.Iterations; index++ {
		started := time.Now()
		observation, err := executeQuery(session, conf, item.SQL)
		if err != nil {
			return workloadResult{}, err
		}
		samples = append(samples, elapsedMS(started))
		if index == 0 {
			expected = observation
		} else if expected != observation {
			return workloadResult{}, fmt.Errorf("unstable result shape for %s", item.Name)
		}
	}

	ordered := append([]float64(nil), samples...)
	sort.Float64s(ordered)
	var total float64
	for _, sample := range samples {
		total += sample
	}
	return workloadResult{
		Name:         item.Name,
		Iterations:   item.Iterations,
		Rows:         expected.Rows,
		DecodedCells: expected.DecodedCells,
		MeanMS:       roundMillis(total / float64(len(samples))),
		P50MS:        roundMillis(percentile(ordered, 0.50)),
		P95MS:        roundMillis(percentile(ordered, 0.95)),
		MinMS:        roundMillis(ordered[0]),

View on GitHub (pinned to c0390bff16)

Solutions

  1. Make the workload SQL deterministic (fixed ORDER BY, stable predicates)
  2. Ensure no concurrent writers modify the queried data during the benchmark
  3. For capture workloads, run the capture phase before mutations, not interleaved
  4. Wrap the comparison or update expected only when instability is intentional in main.go

Example fix

// before
{Name: "point_query", SQL: "SELECT * FROM root.db.d1"}
// after
{Name: "point_query", SQL: "SELECT s0 FROM root.db.d1 WHERE time = 1000"}
Defensive patterns

Strategy: validation

Validate before calling

func isDeterministicSQL(sql string) error {
  low := strings.ToLower(sql)
  if strings.Contains(low, "select *") && !strings.Contains(low, "order by") {
    return fmt.Errorf("workload %q may be non-deterministic: add a deterministic ORDER BY", sql)
  }
  return nil
}

Prevention

When it happens

Trigger: A workload SQL (e.g. SHOW DATABASES after a create, or SELECT with volatile data) returns different rows/results across iterations while the bench loops through workload iterations.

Common situations: Point-query workload hitting data modified by another process during the run; metadata queries where a database/table was created between iterations; timing-affected ORDER BY without a deterministic tiebreaker.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/2865b56de5eba199. Report an issue: GitHub.