{"record":{"id":"a85bb0efc8534ce2","repo":"cocoindex-io/cocoindex","slug":"build-node-delete-requires-at-least-one-primary-ke-a85bb0","errorCode":null,"errorMessage":"build_node_delete requires at least one primary key field","messagePattern":"build_node_delete requires at least one primary key field","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/neo4j/_cypher.py","lineNumber":116,"sourceCode":"    pattern in MERGE just fine.\n    \"\"\"\n    if not pk_fields:\n        raise ValueError(\"build_node_upsert requires at least one primary key field\")\n    cypher = f\"MERGE (n:{_quote(label)} {_key_clause('key', pk_fields)})\"\n    if has_value_fields:\n        cypher += \" SET n += $props\"\n    return cypher\n\n\ndef build_node_delete(label: str, pk_fields: Sequence[str]) -> str:\n    \"\"\"``MATCH (n:`Label` {pk: $key_0, ...}) DETACH DELETE n``.\n\n    DETACH DELETE removes any incident edges as a safety measure for nodes\n    that are also referenced as relationship endpoints — without it, the\n    DELETE would fail on nodes that still have edges.\n    \"\"\"\n    if not pk_fields:\n        raise ValueError(\"build_node_delete requires at least one primary key field\")\n    return f\"MATCH (n:{_quote(label)} {_key_clause('key', pk_fields)}) DETACH DELETE n\"\n\n\ndef build_relationship_upsert(\n    rel_type: str,\n    from_label: str,\n    from_pk_fields: Sequence[str],\n    to_label: str,\n    to_pk_fields: Sequence[str],\n    rel_pk_fields: Sequence[str],\n    has_value_fields: bool,\n) -> str:\n    \"\"\"Three MERGEs: source endpoint, target endpoint, then the relationship.\n\n    Endpoint properties are NOT touched — they are owned by their table's own\n    record handler. We only ``SET r += $props`` on the relationship itself.\n    \"\"\"\n    if not from_pk_fields or not to_pk_fields or not rel_pk_fields:","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/neo4j/_cypher.py#L98-L134","documentation":"build_node_delete generates MATCH (n:Label {pk: ...}) DETACH DELETE n, which needs at least one key property to locate the node. Empty pk_fields would yield a malformed match pattern, so it raises ValueError.","triggerScenarios":"Calling build_node_delete with pk_fields=[] — the node spec has no primary key fields when generating the delete statement.","commonSituations":"Same root cause as the upsert variant: schema declared without a primary key, or an empty field list computed dynamically before deletion reconciliation.","solutions":["Ensure the node's table spec declares a primary key so delete handlers receive pk fields","Pass the same PK fields used for the upsert to build_node_delete","Guard callers to refuse empty PK lists with a clear message before query construction"],"exampleFix":"// before\nbuild_node_delete(label=\"Person\", pk_fields=[])\n// after\nbuild_node_delete(label=\"Person\", pk_fields=[\"id\"])","handlingStrategy":"validation","validationCode":"if not pk_fields:\n    raise ValueError(\"cannot build node delete without primary key fields\")\ncypher = build_node_delete(label=label, pk_fields=pk_fields)","typeGuard":"def non_empty_strs(seq) -> bool:\n    return isinstance(seq, (list, tuple)) and len(seq) > 0 and all(isinstance(x, str) for x in seq)","tryCatchPattern":"try:\n    cypher = build_node_delete(label, pk_fields)\nexcept ValueError as e:\n    if \"at least one primary key\" in str(e):\n        logger.error(\"node %r has no PK; deletes would be unmatchable\", label)\n        raise\n    raise","preventionTips":["Reuse the same PK field list for upsert and delete builders","Assert non-empty primary_key on every node spec at schema construction time","Include PK coverage in schema tests for all node tables"],"tags":["neo4j","cypher","primary-key"],"backgroundTag":"missing-required-argument","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}