tursodatabase/turso · error · ValueError

unsupported engine/mode

Error message

unsupported engine/mode: {key}

What it means

The CSV contains an (engine, mode) pair that has no plotting series defined, so no line can be drawn for it. This is a generic validation guard in read_file: the benchmark CSV's engine and mode columns hold values outside the fixed set of supported SERIES combinations, typically a typo or a newly added engine/mode not yet registered in the SERIES table.

Solutions

  1. Fix the engine/mode spelling in the CSV to match a supported SERIES key
  2. Add the new (engine, mode) pair to the SERIES dict in plot-fts.py
  3. Re-run the benchmark with supported engine/mode settings

Example fix

// before (plot-fts.py)
SERIES = {("turso", "rw"): ...}
// after
SERIES = {("turso", "rw"): ..., ("turso", "ro"): ...}
Defensive patterns

Strategy: validation

Validate before calling

def validate_engine_mode(row):
    if (row["engine"], row["mode"]) not in SERIES:
        raise ValueError(f"unsupported engine/mode: {(row['engine'], row['mode'])}")

Type guard

def is_supported_series(row) -> bool:
    return (row.get("engine"), row.get("mode")) in SERIES

Try / catch

try:
    configuration, runs = read_runs(path, percentile)
except ValueError as e:
    print(f"unsupported series: {e}; update SERIES or fix CSV")

Prevention

When it happens

Trigger: CSV contains an engine or mode value not in SERIES, e.g. a typo like engine='tursodb' or a newly added mode not yet registered in SERIES.

Common situations: Renamed engine in the harness but stale plot script; adding a new benchmark mode and forgetting to update SERIES; hand-edited CSV values.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

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

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"}
        if not required <= set(reader.fieldnames or []):
            raise ValueError(f"{path}: missing benchmark columns")
        for row in reader:
            if row.get("profiled", "false") != "false":
                raise ValueError("profiled timings must not be used for benchmark comparisons")
            current = tuple(row[key] for key in CONFIGURATION)
            if configuration is None:
                configuration = current
            if configuration != current:
                raise ValueError("plot only one configuration at a time")
            key = (row["engine"], row["mode"])
            if key not in SERIES:
                raise ValueError(f"unsupported engine/mode: {key}")
            series = samples.setdefault(key, {query: [] for query in QUERIES})
            query = row["query"]
            seen = runs.setdefault(row["run"], {}).setdefault(key, set())
            if query not in QUERIES or query in seen:
                raise ValueError(f"{path}: unknown or duplicate query {query}")
            seen.add(query)
            series[query].append(read_measurement(row, percentile))
    if not runs:
        raise ValueError(f"{path}: no results found")
    return configuration, runs


def read_measurement(row, percentile):
    queries = int(row["queries"])
    positive_number(queries)
    if row["benchmark"] != "memory":
        seconds = positive_number(row["seconds"])
    if row["benchmark"] == "memory":

View on GitHub (pinned to 8d4a589f8d)