{"record":{"id":"5152cd6c104824a2","repo":"cocoindex-io/cocoindex","slug":"invalid-falkordb-kind-name-r-must-match-a-z","errorCode":null,"errorMessage":"Invalid FalkorDB {kind}: {name!r}. Must match [a-zA-Z_][a-zA-Z0-9_]*.","messagePattern":"Invalid FalkorDB (.+?): (.+?)\\. Must match \\[a-zA-Z_\\]\\[a-zA-Z0-9_\\]\\*\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/falkordb/_cypher.py","lineNumber":44,"sourceCode":"    \"build_relationship_index_drop\",\n    \"build_vector_index_create\",\n    \"build_vector_index_drop\",\n    \"validate_identifier\",\n]\n\n\nIDENTIFIER_RE = re.compile(r\"^[a-zA-Z_][a-zA-Z0-9_]*$\")\n\n\ndef validate_identifier(name: str, kind: str) -> None:\n    \"\"\"Reject anything that isn't ``[a-zA-Z_][a-zA-Z0-9_]*``.\n\n    Cypher labels and property names cannot be parameter-bound, so untrusted\n    names must be validated at API entry — never escaped at query construction\n    time.\n    \"\"\"\n    if not IDENTIFIER_RE.match(name):\n        raise ValueError(\n            f\"Invalid FalkorDB {kind}: {name!r}. Must match [a-zA-Z_][a-zA-Z0-9_]*.\"\n        )\n\n\ndef _quote(name: str) -> str:\n    \"\"\"Backtick-wrap an already-validated identifier for inline use in Cypher.\"\"\"\n    return f\"`{name}`\"\n\n\ndef _key_clause(prefix: str, fields: Sequence[str], var: str) -> str:\n    \"\"\"Build ``{<f1>: $<prefix>_0, <f2>: $<prefix>_1, ...}`` for a MATCH/MERGE pattern.\n\n    ``var`` is unused here but accepted so callers can self-document intent\n    (e.g. ``var=\"n\"`` makes it clear this clause attaches to ``n``).\n    \"\"\"\n    parts = [f\"{_quote(f)}: ${prefix}_{i}\" for i, f in enumerate(fields)]\n    return \"{\" + \", \".join(parts) + \"}\"\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/falkordb/_cypher.py#L26-L62","documentation":"validate_identifier() rejects names used as Cypher labels, relationship types, or property names that don't match [a-zA-Z_][a-zA-Z0-9_]*. Cypher identifiers cannot be parameter-bound, so this library inlines them into query text; to prevent Cypher injection and syntax errors, untrusted names are validated at API entry instead of escaped at query construction time.","triggerScenarios":"Calling any falkordb connector API with a label, rel type, or property/field name containing characters outside [a-zA-Z_][a-zA-Z0-9_]* — e.g. leading digit ('2024_events'), hyphens ('my-label'), dots, spaces, or empty string ''.","commonSituations":"Deriving graph labels from file paths, table names, or user input that wasn't sanitized (e.g. turning 'logs/2024-01' into a label); auto-generating labels from data source names with dashes; localization or prefixed names like '$events'.","solutions":["Sanitize the name before passing it: strip/replace invalid characters so it matches [a-zA-Z_][a-zA-Z0-9_]*.","Verify the name is non-empty and starts with a letter or underscore, not a digit.","If the name must contain special characters, map it to a safe alias and store the mapping in a property instead of the identifier."],"exampleFix":"// before\nlabel = file.path.parent.name  # e.g. '2024-01'\nawait target.declare_node(label=label, ...)\n// after\nimport re\nsafe = re.sub(r'\\W', '_', file.path.parent.name)\nif not re.match(r'[a-zA-Z_]', safe):\n    safe = '_' + safe\nawait target.declare_node(label=safe, ...)","handlingStrategy":"validation","validationCode":"import re\n_IDENT = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*')\n\ndef check_identifier(name: str, kind: str = 'identifier') -> str:\n    if not _IDENT.match(name):\n        raise ValueError(f'{kind} {name!r} must match [a-zA-Z_][a-zA-Z0-9_]*')\n    return name\n\n# before calling any falkordb API:\nlabel = check_identifier(raw_label, 'label')","typeGuard":"def is_valid_identifier(name: object) -> bool:\n    return isinstance(name, str) and bool(re.fullmatch(r'[a-zA-Z_][a-zA-Z0-9_]*', name))","tryCatchPattern":null,"preventionTips":["Sanitize derived names (from paths, table names, user input) with re.sub(r'\\W', '_', name) before use as labels.","Prefix sanitized names with '_' when they start with a digit.","Keep special/variable text in node properties, never in labels or relationship types."],"tags":["cypher","validation","falkordb","identifier"],"backgroundTag":"invalid-identifier-format","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"}