{"record":{"id":"53d8347229128e22","repo":"apache/cassandra","slug":"durations-are-not-allowed-as-map-keys","errorCode":null,"errorMessage":"Durations are not allowed as map keys: ","messagePattern":"Durations are not allowed as map keys: ","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/CQL3Type.java","lineNumber":875,"sourceCode":"                assert values != null : \"Got null values type for a collection\";\n\n                if (!frozen && values.supportsFreezing() && !values.frozen)\n                    throwNestedNonFrozenError(values);\n\n                // we represent supercolumns as maps, internally, and we do allow counters in supercolumns. Thus,\n                // for internal type parsing (think schema) we have to make an exception and allow counters as (map) values\n                if (values.isCounter() && !isInternal)\n                    throw new InvalidRequestException(\"Counters are not allowed inside collections: \" + this);\n\n                if (values.isDuration() && kind == Kind.SET)\n                    throw new InvalidRequestException(\"Durations are not allowed inside sets: \" + this);\n\n                if (keys != null)\n                {\n                    if (keys.isCounter())\n                        throw new InvalidRequestException(\"Counters are not allowed inside collections: \" + this);\n                    if (keys.isDuration())\n                        throw new InvalidRequestException(\"Durations are not allowed as map keys: \" + this);\n                    if (!frozen && keys.supportsFreezing() && !keys.frozen)\n                        throwNestedNonFrozenError(keys);\n                }\n\n                AbstractType<?> valueType = values.prepare(keyspace, udts).getType();\n                switch (kind)\n                {\n                    case LIST:\n                        return new Collection(ListType.getInstance(valueType, !frozen));\n                    case SET:\n                        return new Collection(SetType.getInstance(valueType, !frozen));\n                    case MAP:\n                        assert keys != null : \"Got null keys type for a collection\";\n                        return new Collection(MapType.getInstance(keys.prepare(keyspace, udts).getType(), valueType, !frozen));\n                }\n                throw new AssertionError();\n            }\n","sourceCodeStart":857,"sourceCodeEnd":893,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/CQL3Type.java#L857-L893","documentation":"InvalidRequestException during preparation of a map type: duration types cannot be used as map keys (non-frozen durations are not valid key types). The guard fires while preparing the collection's key type, alongside the analogous counter-in-collection check on values.","triggerScenarios":"Declaring `map<duration, ...>` in CREATE TABLE / ALTER TABLE, or embedding a duration Raw type in the keys position of a map type.","commonSituations":"Users confusing duration with time or timestamp and using it as a map key for interval-keyed lookups.","solutions":["Use `map<time, ...>`, `map<timestamp, ...>`, or `frozen<duration>` is not allowed for keys either — use a text encoding of the duration as the key","Use a duration as the map VALUE instead: map<text, duration> is allowed","Model as a separate table with duration stored in a regular column"],"exampleFix":"// before\nCREATE TABLE t (id uuid PRIMARY KEY, by_interval map<duration, text>);\n// after\nCREATE TABLE t (id uuid PRIMARY KEY, by_interval map<text, duration>);","handlingStrategy":"validation","validationCode":"boolean usesDurationAsMapKey(String cqlTypeDecl) {\n    java.util.regex.Matcher m = java.util.regex.Pattern.compile(\"map\\\\s*<\\\\s*([^,]+),\").matcher(cqlTypeDecl.toLowerCase());\n    return m.find() && m.group(1).trim().equals(\"duration\");\n}","typeGuard":null,"tryCatchPattern":"try { session.execute(ddl); } catch (InvalidQueryException e) { if (e.getMessage().startsWith(\"Durations are not allowed as map keys\")) { /* move duration to value position or use text key */ } else throw e; }","preventionTips":["Duration has no total ordering (months vs days) — exclude it from key/set positions","Use map<text, duration> and keep the duration as the value","Store comparable units (seconds) in bigint keys if interval-keyed lookup is needed"],"tags":["cql","schema","duration","map"],"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"}