openzipkin/zipkin · critical · RuntimeException

schema not installed: apply %s, or set CASSANDRA_ENSURE_SCHE

Error message

schema not installed: apply %s, or set CASSANDRA_ENSURE_SCHEMA=true

What it means

Schema.validate/logAndThrow throws a RuntimeException with 'schema not installed: apply %s, or set CASSANDRA_ENSURE_SCHEMA=true' when the expected Zipkin tables are absent from the configured keyspace. It is logged at ERROR first so the cause is visible in server logs, then rethrown so API endpoints like /health surface it.

Source

Thrown at zipkin-storage/cassandra/src/main/java/zipkin2/storage/cassandra/Schema.java:96

        "schema lacks autocomplete indexing: apply {}, or set CASSANDRA_ENSURE_SCHEMA=true",
        UPGRADE_1);
    }

    if (!hasRemoteService) {
      LOG.warn(
        "schema lacks remote service indexing: apply {}, or set CASSANDRA_ENSURE_SCHEMA=true",
        UPGRADE_2);
    }

    return md;
  }

  static void logAndThrow(String messageFormat, Object... args) {
    String message = messageFormat.formatted(args);
    // Ensure we can look at logs to see the problem. Otherwise, it may only
    // be visible in API error responses, such as /health or /api/v2/traces.
    LOG.error(message);
    throw new RuntimeException(message);
  }

  static void initializeUDTs(CqlSession session, String keyspace) {
    KeyspaceMetadata ks = session.getMetadata().getKeyspace(keyspace).get();
    MutableCodecRegistry codecRegistry =
      (MutableCodecRegistry) session.getContext().getCodecRegistry();

    TypeCodec<UdtValue> annotationUDTCodec =
      codecRegistry.codecFor(ks.getUserDefinedType("annotation").get());
    codecRegistry.register(new AnnotationCodec(annotationUDTCodec));

    LOG.debug("Registering endpoint and annotation UDTs to keyspace {}", keyspace);
    TypeCodec<UdtValue> endpointUDTCodec =
      codecRegistry.codecFor(ks.getUserDefinedType("endpoint").get());
    codecRegistry.register(new EndpointCodec(endpointUDTCodec));
  }

  static final class Metadata {

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Set CASSANDRA_ENSURE_SCHEMA=true (or .ensureSchema(true) in the builder) once so Schema.ensure installs the schema.
  2. Or manually apply the schema resource (zipkin2/schema/cql/*.cql) to the exact keyspace named by CASSANDRA_KEYSPACE.
  3. Verify you are connecting to the intended cluster and keyspace (contact points, DC, keyspace name).

Example fix

// before
CassandraStorage.newBuilder().keyspace("zipkin3").ensureSchema(false).build();

// after
CassandraStorage.newBuilder().keyspace("zipkin3").ensureSchema(true).build();
Defensive patterns

Strategy: validation

Validate before calling

// Before enabling ensureSchema=false, confirm the schema exists
KeyspaceMetadata ks = session.getMetadata().getKeyspace(keyspace).orElseThrow();
if (ks.getTable("span").isEmpty()) throw new IllegalStateException("Install zipkin schema first");

Try / catch

catch (RuntimeException e) { if (e.getMessage() != null && e.getMessage().contains("schema not installed")) applySchema(); else throw e; }

Prevention

When it happens

Trigger: Building CassandraStorage with ensureSchema=false (the default validates) against a keyspace that has no Zipkin schema; pointing at the wrong keyspace or a fresh cluster that was never initialized.

Common situations: Operators that pre-provision schema with the shipped cql files and set CASSANDRA_ENSURE_SCHEMA=false, but apply them to a different keyspace than CASSANDRA_KEYSPACE; new environments cloned without the schema migration step.

Related errors


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