{"record":{"id":"f447761b68ef6cbf","repo":"apache/cassandra","slug":"failed-to-retrieve-target-column-for","errorCode":null,"errorMessage":"Failed to retrieve target column for: ","messagePattern":"Failed to retrieve target column for: ","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/index/sai/StorageAttachedIndex.java","lineNumber":262,"sourceCode":"        }\n\n        String targetColumn = options.get(IndexTarget.TARGET_OPTION_NAME);\n\n        if (targetColumn == null)\n        {\n            throw new InvalidRequestException(\"Missing target column\");\n        }\n\n        if (targetColumn.split(\",\").length > 1)\n        {\n            throw new InvalidRequestException(\"A storage-attached index cannot be created over multiple columns: \" + targetColumn);\n        }\n\n        Pair<ColumnMetadata, IndexTarget.Type> target = TargetParser.parse(metadata, targetColumn);\n\n        if (target == null)\n        {\n            throw new InvalidRequestException(\"Failed to retrieve target column for: \" + targetColumn);\n        }\n\n        // In order to support different index targets on non-frozen map, ie. KEYS, VALUE, ENTRIES, we need to put index\n        // name as part of index file name instead of column name. We only need to check that the target is different\n        // between indexes. This will only allow indexes in the same column with a different IndexTarget.Type.\n        //\n        // Note that: \"metadata.indexes\" already includes current index\n        if (metadata.indexes.stream().filter(index -> index.getIndexClassName().equals(StorageAttachedIndex.class.getName()))\n                            .map(index -> TargetParser.parse(metadata, index.options.get(IndexTarget.TARGET_OPTION_NAME)))\n                            .filter(Objects::nonNull).filter(t -> t.equals(target)).count() > 1)\n        {\n            throw new InvalidRequestException(\"Cannot create more than one storage-attached index on the same column: \" + target.left);\n        }\n\n        Map<String, String> analysisOptions = AbstractAnalyzer.getAnalyzerOptions(options);\n        if (target.left.isPrimaryKeyColumn() && !analysisOptions.isEmpty())\n        {\n            throw new InvalidRequestException(ANALYSIS_ON_KEY_COLUMNS_MESSAGE + new CqlBuilder().append(analysisOptions));","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/index/sai/StorageAttachedIndex.java#L244-L280","documentation":"After the target string passes shape checks, validateOptions calls TargetParser.parse; if it returns null (no matching column/type combination), SAI throws InvalidRequestException(\"Failed to retrieve target column for: \" + targetColumn). This means the target string is syntactically plausible but does not resolve to an indexable column in the table metadata.","triggerScenarios":"CREATE CUSTOM INDEX USING StorageAttachedIndex with a target naming a nonexistent column, an unsupported function wrapper (e.g. keys() on a non-map), or invalid syntax like full() on non-frozen types.","commonSituations":"Typos in column names; using keys()/values()/entries() on set/list columns or plain columns; target on a column dropped before index creation; case-sensitivity mistakes (unquoted \"Email\" vs email).","solutions":["Verify the column name with DESCRIBE TABLE and correct the target","Remove unsupported wrappers — use plain column name for scalars, keys/values/entries only for maps, full() only for frozen collections","Quote the identifier if the column has mixed case","Recreate the index after the column exists"],"exampleFix":"// before\nCREATE CUSTOM INDEX idx ON ks.tbl (Email) USING 'StorageAttachedIndex'; // no such column\n// after\nCREATE CUSTOM INDEX idx ON ks.tbl (email) USING 'StorageAttachedIndex';","handlingStrategy":"validation","validationCode":"if (metadata.getColumn(new ColumnIdentifier(targetColumn, true)) == null && TargetParser.tryParse(metadata, targetColumn) == null)\n    throw new IllegalArgumentException(\"Target does not resolve to an indexable column: \" + targetColumn);","typeGuard":null,"tryCatchPattern":"try { session.execute(ddl); } catch (InvalidRequestException e) { if (e.getMessage().contains(\"Failed to retrieve target column\")) { /* correct column name or wrapper */ } else throw e; }","preventionTips":["Confirm column names via DESCRIBE TABLE before creating indexes (watch identifier case)","Only use keys/values/entries on maps and full() on frozen collections","Run CREATE INDEX statements through a staging environment first"],"tags":["cassandra","sai","invalid-request","schema-validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}