{"record":{"id":"8dfa4b30abfa87a9","repo":"cocoindex-io/cocoindex","slug":"build-relationship-delete-requires-at-least-one-pr","errorCode":null,"errorMessage":"build_relationship_delete requires at least one primary key field","messagePattern":"build_relationship_delete requires at least one primary key field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/falkordb/_cypher.py","lineNumber":133,"sourceCode":"        )\n    cypher = (\n        f\"MERGE (s:{_quote(from_label)} {_key_clause('from_key', from_pk_fields, 's')}) \"\n        f\"MERGE (t:{_quote(to_label)} {_key_clause('to_key', to_pk_fields, 't')}) \"\n        f\"MERGE (s)-[r:{_quote(rel_type)} {_key_clause('rel_key', rel_pk_fields, 'r')}]->(t)\"\n    )\n    if has_value_fields:\n        cypher += \" SET r += $props\"\n    return cypher\n\n\ndef build_relationship_delete(rel_type: str, pk_fields: Sequence[str]) -> str:\n    \"\"\"``MATCH ()-[r:`RelType` {pk: $key_0, ...}]->() DELETE r``.\n\n    Endpoints are intentionally not deleted — they're tracked by their own\n    table handlers and will be deleted by their own reconciler if orphaned.\n    \"\"\"\n    if not pk_fields:\n        raise ValueError(\n            \"build_relationship_delete requires at least one primary key field\"\n        )\n    return (\n        f\"MATCH ()-[r:{_quote(rel_type)} \"\n        f\"{_key_clause('key', pk_fields, 'r')}]->() DELETE r\"\n    )\n\n\ndef build_node_index_create(label: str, fields: Sequence[str]) -> str:\n    \"\"\"``CREATE INDEX FOR (e:`Label`) ON (e.`f1`, e.`f2`, ...)``.\"\"\"\n    if not fields:\n        raise ValueError(\"build_node_index_create requires at least one field\")\n    field_list = \", \".join(f\"e.{_quote(f)}\" for f in fields)\n    return f\"CREATE INDEX FOR (e:{_quote(label)}) ON ({field_list})\"\n\n\ndef build_node_index_drop(label: str, fields: Sequence[str]) -> str:\n    \"\"\"``DROP INDEX FOR (e:`Label`) ON (e.`f1`, ...)``.\"\"\"","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/falkordb/_cypher.py#L115-L151","documentation":"build_relationship_delete() refuses to build a MATCH ()-[r:{...}]->() DELETE r query when pk_fields is empty. The relationship must be identified by its primary key properties; with none, the delete would target all relationships of that type or be invalid, so it raises instead.","triggerScenarios":"Calling build_relationship_delete(rel_type, pk_fields=[]) — the relationship's key field list is empty (mirroring the upsert requirement).","commonSituations":"Relationship declared without its own primary key; cleanup/reconcile path receiving an empty key list because the schema never defined rel keys; dynamic key list built from optional properties.","solutions":["Pass the same rel_pk_fields used in build_relationship_upsert (at least one).","If the relationship has no natural key, add a deterministic id property and use it as the PK.","Trace where pk_fields comes from and fix the empty source (schema config or filtering logic)."],"exampleFix":"// before\nbuild_relationship_delete(rel_type=\"WORKS_AT\", pk_fields=[])\n// after\nbuild_relationship_delete(rel_type=\"WORKS_AT\", pk_fields=[\"since\"])","handlingStrategy":"validation","validationCode":"if not pk_fields:\n    raise ValueError('relationship needs PK fields before delete')\ncypher = build_relationship_delete(rel_type, pk_fields)","typeGuard":"def has_pk_fields(pk_fields: object) -> bool:\n    return isinstance(pk_fields, (list, tuple)) and len(pk_fields) > 0","tryCatchPattern":"try:\n    cypher = build_relationship_delete(rel_type, pk_fields)\nexcept ValueError as e:\n    logger.error('cannot build relationship delete: %s', e)\n    raise ConfigError(f'relationship {rel_type!r} has no PK to match for delete') from e","preventionTips":["Keep rel_pk_fields in one place and share it between upsert and delete.","Validate relationship key configuration at schema load time.","Never build key lists from optional properties without asserting at least one remains."],"tags":["cypher","falkordb","relationship","delete"],"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"}