cocoindex-io/cocoindex · error
build_node_delete requires at least one primary key field
Error message
build_node_delete requires at least one primary key field
What it means
build_node_delete() refuses to build a MATCH ... DETACH DELETE query when pk_fields is empty. Identifying which node to delete requires at least one key property; with none, the query would either delete all nodes or be invalid, so the library raises instead.
Source
Thrown at python/cocoindex/connectors/falkordb/_cypher.py:91
write; otherwise the MERGE alone suffices.
"""
if not pk_fields:
raise ValueError("build_node_upsert requires at least one primary key field")
cypher = f"MERGE (n:{_quote(label)} {_key_clause('key', pk_fields, 'n')})"
if has_value_fields:
cypher += " SET n += $props"
return cypher
def build_node_delete(label: str, pk_fields: Sequence[str]) -> str:
"""``MATCH (n:`Label` {pk: $key_0, ...}) DETACH DELETE n``.
DETACH DELETE removes any incident edges as a safety measure for nodes that
are also referenced as relationship endpoints — without it, the DELETE
would fail on nodes that still have edges.
"""
if not pk_fields:
raise ValueError("build_node_delete requires at least one primary key field")
return (
f"MATCH (n:{_quote(label)} {_key_clause('key', pk_fields, 'n')}) "
f"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 ownView on GitHub (pinned to e84aa99b32)
Solutions
- Add at least one primary key field to the node table schema and pass it as pk_fields.
- Inspect how pk_fields is constructed upstream (config parsing, field filtering) to see why it is empty.
- Use the same key fields for delete as for upsert so matched nodes are consistent.
Example fix
// before build_node_delete(label="Person", pk_fields=[]) // after build_node_delete(label="Person", pk_fields=["person_id"])
Defensive patterns
Strategy: validation
Validate before calling
if not pk_fields:
raise ValueError('node table needs at least one primary key field before delete')
cypher = build_node_delete(label, pk_fields) Type guard
def has_pk_fields(pk_fields: object) -> bool:
return isinstance(pk_fields, (list, tuple)) and len(pk_fields) > 0 Try / catch
try:
cypher = build_node_delete(label, pk_fields)
except ValueError as e:
logger.error('cannot build node delete: %s', e)
raise ConfigError(f'table {label!r} has no primary key to match for delete') from e Prevention
- Reuse the same pk_fields list for upsert and delete paths so they cannot diverge.
- Fail schema validation at startup if a node table has no key fields, before any reconcile runs.
- Log the table schema once at configuration time to catch missing keys early.
When it happens
Trigger: Calling build_node_delete(label, pk_fields=[]) — deleting nodes for a table/handler whose primary key field list is empty.
Common situations: Same root cause as the upsert case: schema defined without a primary key; reconciler cleanup path for a mis-declared table; pk fields list built dynamically and 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
- build_node_upsert requires at least one primary key field
- build_relationship_upsert requires PK fields for from, to, a
- build_relationship_delete requires at least one primary key
- build_node_index_drop requires at least one field
- Invalid FalkorDB {kind}: {name!r}. Must match [a-zA-Z_][a-zA
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/5147785a0b34e844.
Report an issue: GitHub.