{"record":{"id":"b19b13ca2099a8fb","repo":"cocoindex-io/cocoindex","slug":"label-must-contain-only-alphanumeric-characters","errorCode":null,"errorMessage":"{label} must contain only alphanumeric characters, hyphens, and underscores, got: {value!r}","messagePattern":"(.+?) must contain only alphanumeric characters, hyphens, and underscores, got: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/valkey/_target.py","lineNumber":251,"sourceCode":"\n\n# ---------------------------------------------------------------------------\n# Helpers\n# ---------------------------------------------------------------------------\n\n_SAFE_NAME_RE = re.compile(r\"^[a-zA-Z0-9_\\-]+$\")\n_VECTOR_FIELD_NAME = \"vector\"\n\n\ndef _validate_name(value: str, label: str) -> str:\n    \"\"\"Validate that a name contains only safe characters.\n\n    Raises:\n        ValueError: If the name contains characters that could cause key\n            collisions or injection into the Valkey search DSL.\n    \"\"\"\n    if not _SAFE_NAME_RE.match(value):\n        raise ValueError(\n            f\"{label} must contain only alphanumeric characters, \"\n            f\"hyphens, and underscores, got: {value!r}\"\n        )\n    return value\n\n\ndef _vector_to_bytes(vector: list[float] | np.ndarray) -> bytes:  # type: ignore[type-arg]\n    \"\"\"Pack a vector into little-endian float32 bytes for Valkey HASH storage.\"\"\"\n    if isinstance(vector, np.ndarray):\n        return vector.astype(np.float32).tobytes()\n    return struct.pack(f\"<{len(vector)}f\", *vector)\n\n\ndef _make_prefix(index_name: str) -> str:\n    \"\"\"Create the key prefix for documents in an index.\"\"\"\n    return f\"{index_name}:\"\n\n","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/valkey/_target.py#L233-L269","documentation":"Valkey index/doc names are embedded into hash keys (`_make_hash_key`) and into the FT.SEARCH/FT.CREATE DSL, so characters like spaces, colons, and braces could cause key collisions or DSL injection. `_validate_name` enforces `_SAFE_NAME_RE` (alphanumerics, hyphens, underscores) and raises this ValueError naming the offending label and value.","triggerScenarios":"Calling `index_target(name=\"my index\")`, `name=\"ns:docs\"`, or `name=\"docs{0}\"`, or reconcile with a doc_id containing spaces/colons — anywhere `_validate_name` runs on index names or doc ids.","commonSituations":"Deriving index names from filenames or user input ('My Docs 2024'); using namespace-style 'prefix:name' conventions carried over from Redis; doc ids built from URLs or paths containing ':' and '/'.","solutions":["Sanitize the name before passing it: re.sub(r'[^A-Za-z0-9_-]', '_', value) or a similar whitelist.","Replace ':' separators with '-' or '_' (e.g. 'ns-docs' instead of 'ns:docs').","For doc ids, hash or encode unsafe identifiers: _validate_name accepts only [A-Za-z0-9_-], so slugify or hashlib.sha256 the raw id."],"exampleFix":"// before\nindex_target(name=f\"{tenant}:{env}\")\n\n// after\nsafe = re.sub(r\"[^A-Za-z0-9_-]\", \"_\", f\"{tenant}-{env}\")\nindex_target(name=safe)","handlingStrategy":"validation","validationCode":"import re\n_SAFE = re.compile(r\"^[A-Za-z0-9_-]+$\")\nassert _SAFE.match(name), f\"Unsafe Valkey name: {name!r}\"","typeGuard":null,"tryCatchPattern":"try:\n    target = await valkey.index_target(name=name)\nexcept ValueError as e:\n    if \"must contain only alphanumeric\" in str(e):\n        name = re.sub(r\"[^A-Za-z0-9_-]\", \"_\", name)\n        target = await valkey.index_target(name=name)\n    else:\n        raise","preventionTips":["Slugify any name derived from filenames, tenants, or user input before passing it in","Avoid ':' namespace conventions from Redis — use '-' or '_' here","Add a pre-commit/test asserting generated index names match ^[A-Za-z0-9_-]+$"],"tags":["python","validation","naming","valkey"],"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"}