docling-project/docling · error · ValueError

record selectors must be unique

Error message

record selectors must be unique

What it means

Pydantic model_validator on EbcdicLayout: selectors across records must be unique. Duplicate selectors make select()'s next() ambiguous (first match silently wins), so the model rejects the layout rather than allow silent misinterpretation of records.

Source

Thrown at docling/datamodel/backend_options.py:566

            return self.records[0]
        return next(
            (item for item in self.records if item.selector == record_type), None
        )

    @model_validator(mode="after")
    def _validate_records(self) -> "EbcdicLayout":
        if len(self.records) > 1 and self.record_type_field is None:
            raise ValueError(
                "record_type_field is required for a layout with several records"
            )
        if self.record_type_field is not None:
            selectors = [item.selector for item in self.records]
            if None in selectors:
                raise ValueError(
                    "every record needs a selector when record_type_field is set"
                )
            if len(set(selectors)) != len(selectors):
                raise ValueError("record selectors must be unique")
        return self


class EbcdicBackendOptions(BaseBackendOptions):
    """Options specific to the EBCDIC backend."""

    kind: Annotated[Literal["ebcdic"], Field(exclude=True, repr=False)] = "ebcdic"
    encoding: Annotated[
        str,
        Field(
            description=(
                "Python codec used to decode character data, e.g. `cp037` "
                "(US/Canada), `cp500` (international) or `cp1140` (euro)."
            )
        ),
    ] = "cp037"
    layout: Annotated[
        Optional[EbcdicLayout], Field(description="Parsing rules for the file.")

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Give each record a distinct selector value matching the actual codes in the file.
  2. If two codes map to the same schema, either merge them or use distinct selectors and adjust the source data expectation.
  3. Programmatically check len({r.selector for r in records}) == len(records) before building the model.

Example fix

# before
records=[rec(selector='D', ...), rec(selector='D', ...)]  # duplicate -> ValueError

# after
records=[rec(selector='D1', ...), rec(selector='D2', ...)]
Defensive patterns

Strategy: validation

Validate before calling

def selectors_unique(records) -> bool:
    sel = [r.selector for r in records if r.selector is not None]
    return len(set(sel)) == len(sel)

Prevention

When it happens

Trigger: Two EbcdicRecordLayout entries with the same selector string (e.g., both 'D') while record_type_field is set; copy-pasting a record definition and changing fields but not selector; data-entry typos like 'O' vs '0' colliding after normalization.

Common situations: Hand-maintained layout files for legacy EBCDIC exports where record-type codes were duplicated by mistake; generated layouts from a spreadsheet where two rows share a type code.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/cb05f512724bceb2. Report an issue: GitHub.