openzipkin/zipkin · error · IllegalArgumentException

maxTraceCols <= 0

Error message

maxTraceCols <= 0

What it means

Thrown by CassandraStorageBuilder.maxTraceCols(int) when the value is zero or negative. maxTraceCols caps how many span rows are fetched per trace id because a single span id can have multiple rows (client and server share a span id). The guard prevents an unbounded or nonsensical fetch size.

Source

Thrown at zipkin-storage/cassandra/src/main/java/zipkin2/storage/cassandra/CassandraStorageBuilder.java:176

  }

  public B ensureSchema(boolean ensureSchema) {
    if (ensureSchema) {
      this.ensureSchema = Schema::ensure;
    } else {
      this.ensureSchema = Schema::validate;
    }
    return (B) this;
  }

  /**
   * Spans have multiple values for the same id. For example, a client and server contribute to the
   * same span id. When searching for spans by id, the amount of results may be larger than the ids.
   * This defines a threshold which accommodates this situation, without looking for an unbounded
   * number of results.
   */
  public B maxTraceCols(int maxTraceCols) {
    if (maxTraceCols <= 0) throw new IllegalArgumentException("maxTraceCols <= 0");
    this.maxTraceCols = maxTraceCols;
    return (B) this;
  }

  /**
   * How many more index rows to fetch than the user-supplied query limit. Defaults to 3.
   *
   * <p>Backend requests will request {@link QueryRequest#limit()} times this factor rows from
   * Cassandra indexes in attempts to return {@link QueryRequest#limit()} traces.
   *
   * <p>Indexing in cassandra will usually have more rows than trace identifiers due to factors
   * including table design and collection implementation. As there's no way to DISTINCT out
   * duplicates server-side, this over-fetches client-side when {@code indexFetchMultiplier} &gt;
   * 1.
   */
  public B indexFetchMultiplier(int indexFetchMultiplier) {
    if (indexFetchMultiplier <= 0) throw new IllegalArgumentException("indexFetchMultiplier <= 0");
    this.indexFetchMultiplier = indexFetchMultiplier;

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Set a positive value, e.g. maxTraceCols(10000) (the documented default is 10000).
  2. Validate the config-sourced integer before passing it: reject or default values <= 0 at load time.

Example fix

// before
.maxTraceCols(Integer.parseInt(System.getenv("MAX_TRACE_COLS"))) // env unset -> 0

// after
int maxTraceCols = Integer.parseInt(System.getenv().getOrDefault("MAX_TRACE_COLS", "10000"));
if (maxTraceCols <= 0) throw new IllegalArgumentException("MAX_TRACE_COLS must be > 0");
.maxTraceCols(maxTraceCols)
Defensive patterns

Strategy: validation

Validate before calling

int maxTraceCols = config.getInt("cassandra.max-trace-cols", 10000);
if (maxTraceCols <= 0) throw new IllegalArgumentException("maxTraceCols must be > 0, got " + maxTraceCols);
builder.maxTraceCols(maxTraceCols);

Prevention

When it happens

Trigger: Calling maxTraceCols(0) or maxTraceCols(-5) on CassandraStorage.newBuilder(); computing the value from user input or config that defaulted to 0 when parsing failed.

Common situations: Setting maxTraceCols from an environment variable or properties file where a typo or missing value parses to 0; porting older configs that used a different name.

Related errors


AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14). Data as JSON: /api/errors/71205b2c2a0f3be0. Report an issue: GitHub.