{"record":{"id":"16ce5b09691108ab","repo":"cocoindex-io/cocoindex","slug":"build-node-index-create-requires-at-least-one-fiel-16ce5b","errorCode":null,"errorMessage":"build_node_index_create requires at least one field","messagePattern":"build_node_index_create requires at least one field","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/neo4j/_cypher.py","lineNumber":173,"sourceCode":"        raise ValueError(\n            \"build_relationship_delete requires at least one primary key field\"\n        )\n    return (\n        f\"MATCH ()-[r:{_quote(rel_type)} {_key_clause('key', pk_fields)}]->() DELETE r\"\n    )\n\n\ndef build_node_index_create(\n    name: str,\n    label: str,\n    fields: Sequence[str],\n) -> str:\n    \"\"\"``CREATE INDEX <name> IF NOT EXISTS FOR (n:`Label`) ON (n.`f1`, n.`f2`, ...)``.\n\n    Neo4j requires named indexes; ``IF NOT EXISTS`` makes setup idempotent.\n    \"\"\"\n    if not fields:\n        raise ValueError(\"build_node_index_create requires at least one field\")\n    field_list = \", \".join(f\"n.{_quote(f)}\" for f in fields)\n    return (\n        f\"CREATE INDEX {_quote(name)} IF NOT EXISTS \"\n        f\"FOR (n:{_quote(label)}) ON ({field_list})\"\n    )\n\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,","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/neo4j/_cypher.py#L155-L191","documentation":"build_node_index_create generates CREATE INDEX ... FOR (n:Label) ON (n.f1, n.f2, ...). Neo4j indexes require at least one indexed property; an empty fields list would produce invalid DDL, so it raises ValueError.","triggerScenarios":"Calling build_node_index_create(name=..., label=..., fields=[]) — no property fields supplied for the index.","commonSituations":"Index list built from config where the fields key was omitted/empty; code that conditionally adds fields and ends up with none; copying an index helper call without fields.","solutions":["Pass at least one field to index (e.g. [\"id\"] or the properties you query on)","Skip calling build_node_index_create entirely when no fields are configured instead of calling it with an empty list","Validate the index config at load time: reject index entries with no fields"],"exampleFix":"// before\nbuild_node_index_create(name=\"person_email_idx\", label=\"Person\", fields=[])\n// after\nbuild_node_index_create(name=\"person_email_idx\", label=\"Person\", fields=[\"email\"])","handlingStrategy":"validation","validationCode":"if not fields:\n    raise ValueError(f\"index {name!r} configured with no fields; skip creation\")\nddl = build_node_index_create(name=name, label=label, fields=fields)","typeGuard":"def indexable(fields) -> bool:\n    return isinstance(fields, (list, tuple)) and len(fields) > 0","tryCatchPattern":"try:\n    ddl = build_node_index_create(name, label, fields)\nexcept ValueError as e:\n    if \"requires at least one field\" in str(e):\n        logger.warning(\"skipping index %r: no fields configured\", name)\n    else:\n        raise","preventionTips":["Skip empty index configs in setup code instead of invoking the builder","Validate index configuration at load time (each index entry needs >=1 field)","Only create indexes for property combinations your queries actually filter on"],"tags":["neo4j","cypher","index","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"}