apache/cassandra · error · InvalidRequestException

Invalid map literal for

Error message

Invalid map literal for %s: bind variables are not supported inside collection literals

What it means

Cassandra map literals (e.g. `SET m = {'a': 1}`) cannot contain bind markers inside them; the whole literal must either be a literal or bound as a single value. During prepare, if any key or term of the map literal contains a bind marker, preparation fails.

Solutions

  1. Bind the entire map as one parameter: `SET m = ?` and pass a Map value.
  2. Use literals directly in the map: `SET m = {'key': 'value'}`.
  3. For a single key update use positional key binding on the accessor form `m[?] = ?`, not inside a literal.

Example fix

// before
"UPDATE t SET m = {? : ?} WHERE k=?"
// after
"UPDATE t SET m[?] = ? WHERE k=?"  // or bind whole map: SET m = ?
Defensive patterns

Strategy: validation

Validate before calling

if (query.matches(".*\{[^}]*\?.*\}.*")) throw new IllegalArgumentException("bind markers not allowed inside map literals");

Try / catch

try { session.prepare(sql); } catch (InvalidRequestException e) { if (e.getMessage().contains("bind variables are not supported inside collection literals")) { /* rewrite query */ } else throw e; }

Prevention

When it happens

Trigger: Preparing a statement like `INSERT ... SET m = {? : ?}` or `UPDATE ... SET m['?'] = ?` where a bind marker appears inside a map literal's entries.

Common situations: Developers assuming named parameters work anywhere in a statement; query builders interpolating bind markers into collection literals; migrating code from concatenation to parameterized queries.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/8fc6e98e04ab450d. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/terms/Maps.java:195

        public Term prepare(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
        {
            validateAssignableTo(keyspace, receiver);

            ColumnSpecification keySpec = Maps.keySpecOf(receiver);
            ColumnSpecification valueSpec = Maps.valueSpecOf(receiver);
            // In CQL maps are represented as a list of key value pairs (e.g. {k1 : v1, k2 : v2, ...}).
            // Whereas, internally maps are serialized as a lists where each key is followed by its value (e.g. [k1, v1, k2, v2, ...])
            // Therefore, we must go from one format to another.
            List<Term> values = new ArrayList<>(entries.size() << 1);
            boolean allTerminal = true;
            for (Pair<Term.Raw, Term.Raw> entry : entries)
            {
                Term k = entry.left.prepare(keyspace, keySpec);
                Term v = entry.right.prepare(keyspace, valueSpec);

                if (k.containsBindMarker() || v.containsBindMarker())
                    throw new InvalidRequestException(String.format("Invalid map literal for %s: bind variables are not supported inside collection literals", receiver.name));

                if (k instanceof Term.NonTerminal || v instanceof Term.NonTerminal)
                    allTerminal = false;

                values.add(k);
                values.add(v);
            }
            MultiElements.DelayedValue value = new MultiElements.DelayedValue((MultiElementType<?>) receiver.type.unwrap(), values);
            return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
        }

        private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
        {
            AbstractType<?> type = receiver.type.unwrap();

            if (!(type instanceof MapType))
                throw new InvalidRequestException(String.format("Invalid map literal for %s of type %s", receiver.name, receiver.type.asCQL3Type()));

View on GitHub (pinned to 88fd0f6a0e)