apache/cassandra · error · ParseError

Invalid composite string, it should start and end with match

Error message

Invalid composite string, it should start and end with matching parentheses: {}

What it means

When parsing a composite value (map, set, list, tuple, or user type) from CSV during COPY FROM, the string must start and end with a matched pair of parentheses/brackets/braces. Anything shorter than 2 chars or with mismatched outer brackets is rejected with this ParseError.

Source

Thrown at pylib/cqlshlib/copyutil.py:1989

            types, "val" should be at least 2 characters long, the first char should be an
            open parenthesis and the last char should be a matching closing parenthesis. We could also
            check exactly which parenthesis type depending on the caller, but I don't want to enforce
            too many checks that don't necessarily provide any additional benefits, and risk breaking
            data that could previously be imported, even if strictly speaking it is incorrect CQL.
            For example, right now we accept sets that start with '[' and ']', I don't want to break this
            by enforcing '{' and '}' in a minor release.
            """
            def is_open_paren(cc):
                return cc == '{' or cc == '[' or cc == '('

            def is_close_paren(cc):
                return cc == '}' or cc == ']' or cc == ')'

            def paren_match(c1, c2):
                return (c1 == '{' and c2 == '}') or (c1 == '[' and c2 == ']') or (c1 == '(' and c2 == ')')

            if len(val) < 2 or not paren_match(val[0], val[-1]):
                raise ParseError('Invalid composite string, it should start and end with matching parentheses: {}'
                                 .format(val))

            ret = []
            last = 1
            level = 0
            quote = False
            for i, c in enumerate(val):
                if c == '\'':
                    quote = not quote
                elif not quote:
                    if is_open_paren(c):
                        level += 1
                    elif is_close_paren(c):
                        level -= 1
                    elif c == sep and level == 1:
                        ret.append(val[last:i])
                        last = i + 1
            else:

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Wrap collection values in matching delimiters: list/tuple use [..]/(..), set/map use {..}, UDT uses (..)
  2. Check CSV quoting so delimiters are not consumed by the CSV parser
  3. Inspect the offending row in the CSV and correct the value format

Example fix

// before
1, a,b
// after (for a set column)
1,"{a,b}"
Defensive patterns

Strategy: validation

Validate before calling

import re
for col, v in row.items():
    if col in collection_cols:
        pairs = {'{':'}','[':']','(':')'}
        if not (v and v[0] in pairs and v[-1] == pairs[v[0]]):
            raise ValueError(f"{col}: value {v!r} lacks matching delimiters")

Try / catch

try:
    run_copy_from(...)
except ParseError as e:
    print(f"Malformed collection value: {e}")  # fix that CSV cell

Prevention

When it happens

Trigger: COPY FROM a CSV cell for a collection/UDT column whose value lacks the wrapping braces, e.g. 'a,b' instead of '{a,b}' for a set, or '(1,2]' mixing bracket types, or an empty cell parsed as a collection.

Common situations: Hand-edited CSVs missing the outer braces, exports from other tools that serialize collections differently, truncated fields, quoting issues that strip the brackets during CSV parsing.

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/516d593e618c8ab5. Report an issue: GitHub.