tursodatabase/turso · error · ValueError

plot only one configuration at a time

Error message

plot only one configuration at a time

What it means

read_runs groups benchmark runs for plotting and requires all input CSVs to share one configuration tuple (the CONFIGURATION columns). It raises this ValueError when a file's configuration differs from the first file's, because the plotter renders a single configuration per chart.

Solutions

  1. Plot one configuration per invocation: pass only CSVs sharing identical CONFIGURATION columns.
  2. Split the invocation into multiple plot runs, one per configuration.
  3. Regenerate the mismatched CSVs with the intended configuration.

Example fix

# before
python plot-fts.py budget-1000/results.csv budget-5000/results.csv
# after
python plot-fts.py budget-1000/results.csv
Defensive patterns

Strategy: validation

Validate before calling

import csv
def config_of(p):
    r = csv.DictReader(open(p))
    return tuple(next(r)[k] for k in CONFIGURATION)
assert len({config_of(p) for p in paths}) == 1, 'pass only files from one configuration per plot'

Try / catch

try:
    config, samples = read_runs(paths)
except ValueError as e:
    if 'only one configuration' in str(e):
        print('Fix: split the plot into one invocation per configuration')
    else:
        raise

Prevention

When it happens

Trigger: Calling read_runs (from main or read_sweep) with CSV files whose CONFIGURATION column values differ between files.

Common situations: Combining benchmark outputs from different sample budgets, percentiles, or fixture settings; plotting files from two separate benchmark campaigns on one command line.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of tursodatabase/turso@8d4a589f8d (2026-09-20). Data as JSON: /api/errors/876b183c57a02260. Report an issue: GitHub.

Appendix: source

Thrown at perf/fts/plot/plot-fts.py:77

            configuration = current
        if current != configuration or (points and set(samples) != set(next(iter(points.values())))):
            raise ValueError("sweep files must match benchmark, sample budget, fixture and engine/mode series")
        points[connections] = samples
    if not points:
        raise ValueError("no sweep results found")
    return configuration, dict(sorted(points.items()))


def read_runs(paths, percentile="p50"):
    configuration = None
    samples = {}
    expected_series = None
    for path in paths:
        current, runs = read_file(path, percentile, samples)
        if configuration is None:
            configuration = current
        if configuration != current:
            raise ValueError("plot only one configuration at a time")
        for run in runs.values():
            if expected_series is None:
                expected_series = set(run)
            if set(run) != expected_series or any(seen != set(QUERIES) for seen in run.values()):
                raise ValueError(f"{path}: each run must contain the same series and all six query cases")
    if configuration is None:
        raise ValueError("no results found")
    configuration = dict(zip(CONFIGURATION, configuration))
    configuration["percentile"] = percentile
    return configuration, samples


def read_file(path, percentile, samples):
    configuration = None
    runs = {}
    with path.open(newline="") as stream:
        reader = csv.DictReader(stream)
        required = set(CONFIGURATION) | {"engine", "mode", "run", "query", "queries"}

View on GitHub (pinned to 8d4a589f8d)