cocoindex-io/cocoindex · error

build_relationship_upsert requires PK fields for from, to, a

Error message

build_relationship_upsert requires PK fields for from, to, and the relationship

What it means

build_relationship_upsert() requires non-empty primary key fields for the source node, the target node, AND the relationship itself, because it emits three MERGE clauses — one per endpoint and one for the relationship — each of which needs key properties to match on. If any of the three lists is empty it raises instead of producing a query that would match non-deterministically.

Source

Thrown at python/cocoindex/connectors/falkordb/_cypher.py:113

    )


def build_relationship_upsert(
    rel_type: str,
    from_label: str,
    from_pk_fields: Sequence[str],
    to_label: str,
    to_pk_fields: Sequence[str],
    rel_pk_fields: Sequence[str],
    has_value_fields: bool,
) -> str:
    """Three MERGEs: source endpoint, target endpoint, then the relationship.

    Endpoint properties are NOT touched — they are owned by their table's own
    record handler. We only ``SET r += $props`` on the relationship itself.
    """
    if not from_pk_fields or not to_pk_fields or not rel_pk_fields:
        raise ValueError(
            "build_relationship_upsert requires PK fields for from, to, and the relationship"
        )
    cypher = (
        f"MERGE (s:{_quote(from_label)} {_key_clause('from_key', from_pk_fields, 's')}) "
        f"MERGE (t:{_quote(to_label)} {_key_clause('to_key', to_pk_fields, 't')}) "
        f"MERGE (s)-[r:{_quote(rel_type)} {_key_clause('rel_key', rel_pk_fields, 'r')}]->(t)"
    )
    if has_value_fields:
        cypher += " SET r += $props"
    return cypher


def build_relationship_delete(rel_type: str, pk_fields: Sequence[str]) -> str:
    """``MATCH ()-[r:`RelType` {pk: $key_0, ...}]->() DELETE r``.

    Endpoints are intentionally not deleted — they're tracked by their own
    table handlers and will be deleted by their own reconciler if orphaned.
    """

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Provide PK fields for both endpoints (the same keys their node tables use) and at least one PK field for the relationship (add an id/hash property if it has no natural key).
  2. Verify the relationship mapping's key_fields configuration covers from, to, and rel entries.
  3. Check upstream field filtering that may strip the key columns.

Example fix

// before
build_relationship_upsert(from_label="Person", from_pk_fields=[], to_label="Company", to_pk_fields=["id"], rel_type="WORKS_AT", rel_pk_fields=[])
// after
build_relationship_upsert(from_label="Person", from_pk_fields=["person_id"], to_label="Company", to_pk_fields=["id"], rel_type="WORKS_AT", rel_pk_fields=["since"])
Defensive patterns

Strategy: validation

Validate before calling

for name, fields in (('from', from_pk_fields), ('to', to_pk_fields), ('rel', rel_pk_fields)):
    if not fields:
        raise ValueError(f'relationship needs PK fields for {name}')
cypher = build_relationship_upsert(from_label, from_pk_fields, to_label, to_pk_fields, rel_type, rel_pk_fields, ...)

Type guard

def all_have_keys(*field_lists: object) -> bool:
    return all(isinstance(f, (list, tuple)) and len(f) > 0 for f in field_lists)

Try / catch

try:
    cypher = build_relationship_upsert(...)
except ValueError as e:
    logger.error('relationship upsert misconfigured: %s', e)
    raise ConfigError(f'relationship {rel_type!r} must define PKs for endpoints and itself') from e

Prevention

When it happens

Trigger: Calling build_relationship_upsert with from_pk_fields=[], to_pk_fields=[], or rel_pk_fields=[] — e.g. a relationship mapping that defines endpoint labels but no key fields, or a relationship with no properties so the author passed an empty rel key list.

Common situations: Relationship schema omitted the relationship's own primary key assuming it wasn't needed; endpoint node tables declared without PKs; refactoring renamed key fields and the lists ended up empty.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/2aca4693cd7e8eff. Report an issue: GitHub.