cocoindex-io/cocoindex · error · ValueError
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 performs three MERGEs: source node, target node, then the relationship. Each MERGE needs its own key clause, so all three PK lists (from_pk_fields, to_pk_fields, rel_pk_fields) must be non-empty; any empty one makes the pattern invalid and raises ValueError.
Source
Thrown at python/cocoindex/connectors/neo4j/_cypher.py:135
return f"MATCH (n:{_quote(label)} {_key_clause('key', pk_fields)}) DETACH DELETE n"
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)}) "
f"MERGE (t:{_quote(to_label)} {_key_clause('to_key', to_pk_fields)}) "
f"MERGE (s)-[r:{_quote(rel_type)} {_key_clause('rel_key', rel_pk_fields)}]->(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
- Declare primary key fields for the relationship record itself in addition to both endpoint tables
- Verify both from/to node specs have non-empty primary keys
- Fail fast in your schema-loading code if any of the three PK lists is empty
Example fix
// before build_relationship_upsert(rel_type="MENTIONS", from_label="Doc", to_label="Doc", from_pk_fields=["id"], to_pk_fields=["id"], rel_pk_fields=[]) // after build_relationship_upsert(rel_type="MENTIONS", from_label="Doc", to_label="Doc", from_pk_fields=["id"], to_pk_fields=["id"], rel_pk_fields=["ordinal"])
Defensive patterns
Strategy: validation
Validate before calling
assert from_pk_fields and to_pk_fields and rel_pk_fields, (
"relationship upsert needs PK fields for both endpoints and the relationship"
)
build_relationship_upsert(rel_type=rel_type, from_label=from_label, to_label=to_label,
from_pk_fields=from_pk_fields, to_pk_fields=to_pk_fields, rel_pk_fields=rel_pk_fields) Type guard
def all_have_pks(from_pk, to_pk, rel_pk) -> bool:
return bool(from_pk) and bool(to_pk) and bool(rel_pk) Try / catch
try:
cypher = build_relationship_upsert(...)
except ValueError as e:
if "requires PK fields" in str(e):
logger.error("relationship %r or an endpoint lacks a primary key", rel_type)
raise
raise Prevention
- Model the relationship with its own primary key fields, not just endpoint keys
- Ensure both endpoint node tables declare primary keys before defining relationships
- Validate relationship specs at load: all three PK lists must be non-empty
When it happens
Trigger: Calling build_relationship_upsert with an empty from_pk_fields, to_pk_fields, or rel_pk_fields — e.g. the relationship record, one of its endpoint tables, or the relationship itself has no primary key fields declared.
Common situations: Relationship rows defined without a PK (assuming endpoints alone identify them); endpoint node tables defined without primary keys; dynamic schemas where one endpoint's PK list was computed as 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
- build_relationship_delete requires at least one primary key
- build_relationship_upsert requires PK fields for from, to, a
- build_node_upsert requires at least one primary key field
- build_node_delete requires at least one primary key field
- build_node_index_create requires at least one field
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/8707f34b395da902.
Report an issue: GitHub.