{"record":{"id":"704d624aca278820","repo":"apache/cassandra","slug":"cql-type","errorCode":null,"errorMessage":"CQL type ","messagePattern":"CQL type ","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/index/sai/analyzer/AbstractAnalyzer.java","lineNumber":97,"sourceCode":"\n        default void close()\n        {\n        }\n    }\n\n    public static AnalyzerFactory fromOptions(IndexTermType indexTermType, Map<String, String> options)\n    {\n        if (hasNonTokenizingOptions(options))\n        {\n            if (indexTermType.isString())\n            {\n                // validate options\n                NonTokenizingOptions.fromMap(options);\n                return () -> new NonTokenizingAnalyzer(indexTermType, options);\n            }\n            else\n            {\n                throw new InvalidRequestException(\"CQL type \" + indexTermType.asCQL3Type() + \" cannot be analyzed.\");\n            }\n        }\n\n        return null;\n    }\n\n    private static boolean hasNonTokenizingOptions(Map<String, String> options)\n    {\n        return options.keySet().stream().anyMatch(NonTokenizingOptions::hasOption);\n    }\n\n    public static Map<String, String> getAnalyzerOptions(Map<String, String> options)\n    {\n        return options.entrySet().stream()\n                      .filter(e -> NonTokenizingOptions.hasOption(e.getKey()))\n                      .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\n    }\n","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/index/sai/analyzer/AbstractAnalyzer.java#L79-L115","documentation":"AbstractAnalyzer.fromOptions only supports analyzers on text-like CQL types. When analyzer options (or a non-tokenizing analyzer) are supplied for a CQL type that cannot be analyzed (e.g., int, uuid, collections), it throws InvalidRequestException 'CQL type <type> cannot be analyzed.'","triggerScenarios":"CREATE CUSTOM INDEX ... WITH OPTIONS containing analyzer keys (e.g., 'analyzer_class', 'case_sensitive', normalization/tokenizer options) on a non-text column such as int, timestamp, uuid, or frozen collections.","commonSituations":"Copying index DDL from a text column to a numeric/UUID column; generic tooling that appends analyzer options to every SAI index; typo making the target resolve to the wrong column.","solutions":["Remove analyzer options from the index on the non-text column.","Only apply NonTokenizingOptions/analyzer options to text and ascii columns.","Verify the target column in the CREATE INDEX statement is the intended text column."],"exampleFix":"// before\nCREATE CUSTOM INDEX ON ks.tbl (int_col) USING 'StorageAttachedIndex'\n  WITH OPTIONS = {'case_sensitive': 'false'};\n// after\nCREATE CUSTOM INDEX ON ks.tbl (int_col) USING 'StorageAttachedIndex';","handlingStrategy":"validation","validationCode":"const ANALYZABLE = new Set(['text','ascii']); if (Object.keys(options).some(k => ['analyzer_class','case_sensitive','normalize_upper','normalize_lower'].includes(k)) && !ANALYZABLE.has(columnType)) throw new Error(`CQL type ${columnType} cannot be analyzed`);","typeGuard":null,"tryCatchPattern":"catch (InvalidRequestException e) { if (e.getMessage().includes('cannot be analyzed')) { // retry without analyzer options } }","preventionTips":["Apply analyzer options only to text/ascii columns","Make DDL generators column-type-aware","Lint index options against the target column's CQL type"],"tags":["cassandra","sai","analyzer","invalid-options"],"backgroundTag":"unsupported-config-value","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}