{"record":{"id":"f351faed94412ec2","repo":"cocoindex-io/cocoindex","slug":"build-relationship-index-create-requires-at-least-f351fa","errorCode":null,"errorMessage":"build_relationship_index_create requires at least one field","messagePattern":"build_relationship_index_create requires at least one field","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/neo4j/_cypher.py","lineNumber":197,"sourceCode":"\n\ndef build_node_index_drop(name: str) -> str:\n    \"\"\"``DROP INDEX <name> IF EXISTS``.\n\n    Unlike FalkorDB's by-(label, field) drop, Neo4j drops indexes by name\n    regardless of kind (node or relationship).\n    \"\"\"\n    return f\"DROP INDEX {_quote(name)} IF EXISTS\"\n\n\ndef build_relationship_index_create(\n    name: str,\n    rel_type: str,\n    fields: Sequence[str],\n) -> str:\n    \"\"\"``CREATE INDEX <name> IF NOT EXISTS FOR ()-[r:`RelType`]-() ON (r.`f1`, ...)``.\"\"\"\n    if not fields:\n        raise ValueError(\"build_relationship_index_create requires at least one field\")\n    field_list = \", \".join(f\"r.{_quote(f)}\" for f in fields)\n    return (\n        f\"CREATE INDEX {_quote(name)} IF NOT EXISTS \"\n        f\"FOR ()-[r:{_quote(rel_type)}]-() ON ({field_list})\"\n    )\n\n\ndef build_relationship_index_drop(name: str) -> str:\n    \"\"\"``DROP INDEX <name> IF EXISTS``.\n\n    Same DROP statement as for node indexes — Neo4j unifies the namespace.\n    \"\"\"\n    return f\"DROP INDEX {_quote(name)} IF EXISTS\"\n\n\ndef build_constraint_create(\n    name: str,\n    label: str,","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/neo4j/_cypher.py#L179-L215","documentation":"This ValueError is raised by build_relationship_index_create when the fields sequence used to build a Neo4j relationship index is empty. A Cypher relationship index must index at least one property, so generating the CREATE INDEX statement with no fields would produce invalid Cypher. The library throws early to fail at statement-construction time rather than at database execution time.","triggerScenarios":"Calling build_relationship_index_create(name, rel_type, fields=[]) with an empty list/tuple of field names — e.g. deriving fields from a schema that produced no indexed columns, or passing a literal empty list.","commonSituations":"Schema introspection returning no indexed fields for a relationship type; a config file where the 'index_fields' key is present but empty; filtering fields by type and accidentally excluding all of them.","solutions":["Pass at least one relationship property name in fields, e.g. ['weight'].","If fields are computed, check the list before calling and skip index creation when empty.","Verify the upstream schema/config actually populates the fields collection."],"exampleFix":"// before\nbuild_relationship_index_create(\"rel_weight_idx\", \"KNOWS\", [])\n// after\nbuild_relationship_index_create(\"rel_weight_idx\", \"KNOWS\", [\"weight\"])","handlingStrategy":"validation","validationCode":"if not fields:\n    raise ValueError(\"fields must contain at least one property name\")  # or skip index creation\nbuild_relationship_index_create(name, rel_type, fields)","typeGuard":null,"tryCatchPattern":"try:\n    stmt = build_relationship_index_create(name, rel_type, fields)\nexcept ValueError as e:\n    logging.warning(\"skipping relationship index %s: %s\", name, e)","preventionTips":["Assert len(fields) > 0 in the config loader before index setup","Log a warning and skip instead of building an index when a rel type has no indexed fields","Keep index field lists derived from the same schema source as the data"],"tags":["neo4j","cypher","validation","empty-argument"],"backgroundTag":"empty-required-field","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"}