{"record":{"id":"6ae34ca947b56a9b","repo":"openzipkin/zipkin","slug":"annotationquerystring-query-unsupported-due-to-m","errorCode":null,"errorMessage":"{annotationQueryString} query unsupported due to missing annotation_query index","messagePattern":"(.+?) query unsupported due to missing annotation_query index","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"zipkin-storage/cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanStore.java","lineNumber":133,"sourceCode":"   * <p>The amount of backend calls increase in dimensions of query complexity, days of data, and\n   * limit of traces requested. For example, a query like \"http.path=/foo and error\" will be two\n   * select statements for the expression, possibly follow-up calls for pagination (when over 5K\n   * rows match). Once IDs are parsed, there's one call for each 5K rows of span data. This means\n   * \"http.path=/foo and error\" is minimally 3 network calls, the first two in parallel.\n   */\n  @Override public Call<List<List<Span>>> getTraces(QueryRequest request) {\n    if (!searchEnabled) return Call.emptyList();\n\n    TimestampRange timestampRange = timestampRange(request, indexTtl);\n    // If we have to make multiple queries, over fetch on indexes as they don't return distinct\n    // (trace id, timestamp) rows. This mitigates intersection resulting in < limit traces\n    final int traceIndexFetchSize = request.limit() * indexFetchMultiplier;\n    List<Call<Map<String, Long>>> callsToIntersect = new ArrayList<>();\n\n    List<String> annotationKeys = CassandraUtil.annotationKeys(request);\n    for (String annotationKey : annotationKeys) {\n      if (spanTable == null) {\n        throw new IllegalArgumentException(request.annotationQueryString()\n          + \" query unsupported due to missing annotation_query index\");\n      }\n      callsToIntersect.add(\n        spanTable.newCall(request.serviceName(), annotationKey, timestampRange, traceIndexFetchSize)\n      );\n    }\n\n    // Bucketed calls can be expensive when service name isn't specified. This guards against abuse.\n    if (request.remoteServiceName() != null\n      || request.spanName() != null\n      || request.minDuration() != null\n      || callsToIntersect.isEmpty()) {\n      callsToIntersect.add(newBucketedTraceIdCall(request, timestampRange, traceIndexFetchSize));\n    }\n\n    if (callsToIntersect.size() == 1) {\n      return callsToIntersect.get(0)\n        .map(traceIdsSortedByDescTimestamp())","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin-storage/cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanStore.java#L115-L151","documentation":"CassandraSpanStore.getTraces throws IllegalArgumentException ('{annotationQueryString} query unsupported due to missing annotation_query index') when a QueryRequest includes annotation/tag filters but the connected Cassandra schema lacks the annotation_query index table. Zipkin's Cassandra schema is versioned; older schemas (or custom keyspaces) without this table cannot serve annotation queries, so the request is rejected rather than silently returning wrong results.","triggerScenarios":"QueryRequest with annotationQueryString (e.g. QueryRequest.newBuilder().serviceName(...).addAnnotation(...)) against a Cassandra keyspace created with an older schema or with ensureSchema against a pre-annotation-index layout where the spanTable factory is null.","commonSituations":"Upgrading Zipkin while reusing an old 'zipkin'/'zipkin2' keyspace that predates annotation_query; pointing at a keyspace installed by a much older release; environments where schema migration was never run.","solutions":["Install/upgrade the Cassandra schema to the current zipkin3 layout (let ensureSchema=true run against a fresh keyspace, or apply the schema upgrade scripts)","Point the server at a keyspace name matching the new schema (default zipkin3) instead of the legacy one","As a workaround, remove annotation/tag filters from the query so it uses supported indexes"],"exampleFix":"# before\nzipkin.storage.type=cassandra\nzipkin.storage.cassandra.keyspace=zipkin2   # legacy schema, no annotation_query\n\n# after\nzipkin.storage.type=cassandra\nzipkin.storage.cassandra.keyspace=zipkin3\nzipkin.storage.cassandra.ensure-schema=true","handlingStrategy":"validation","validationCode":"// before querying, check schema capability\nboolean supportsAnnotationQuery = storage.spanStore() instanceof CassandraSpanStore;\n// simplest: ensure keyspace was created with the current schema (zipkin3) and annotation_query exists\n// cqlsh: DESCRIBE TABLE zipkin3.annotation_query;","typeGuard":null,"tryCatchPattern":"catch (IllegalArgumentException e) if message contains 'missing annotation_query index' -> fall back to a query without annotation filters and surface a UI banner that the schema needs migration","preventionTips":["Run schema migrations together with Zipkin version upgrades","Verify required tables (annotation_query, remote_service_by_service) exist after any schema change"],"tags":["zipkin","cassandra","schema","query","annotation-index"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}