cocoindex-io/cocoindex · error · ValueError

Invalid SurrealDB {kind}: {name!r}. Must match [a-zA-Z_][a-z

Error message

Invalid SurrealDB {kind}: {name!r}. Must match [a-zA-Z_][a-zA-Z0-9_]*.

What it means

SurrealQL identifiers (table names, index names, column names) used inline in generated SurrealQL must be safe: start with a letter or underscore and contain only alphanumerics/underscores. CocoIndex validates all such names up front (in __init__, declare_vector_index, table_target, relation_target) to prevent syntax errors and injection via crafted names.

Source

Thrown at python/cocoindex/connectors/surrealdb/_target.py:81

from cocoindex.resources import schema as res_schema
from cocoindex._internal.context_keys import ContextKey, ContextProvider

# ---------------------------------------------------------------------------
# Identifier validation & record ID formatting
# ---------------------------------------------------------------------------

_IDENTIFIER_RE = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")


def _validate_identifier(name: str, kind: str) -> None:
    """Validate that *name* is a safe SurrealQL identifier.

    Raises :class:`ValueError` if the name contains characters that are not
    alphanumeric or underscore, or starts with a digit.
    """
    if not _IDENTIFIER_RE.match(name):
        raise ValueError(
            f"Invalid SurrealDB {kind}: {name!r}. Must match [a-zA-Z_][a-zA-Z0-9_]*."
        )


def _format_record_id(value: Any) -> str:
    """Format a record ID for inline use in SurrealQL, preserving type.

    * ``int`` / ``float`` → bare numeric literal (``123``, ``3.14``)
    * ``str`` (and everything else) → backtick-quoted with ``\\`` and
      backtick escaping (`` `alice` ``, `` `has\\`tick` ``)
    """
    if isinstance(value, (int, float)):
        return str(value)
    s = str(value)
    s = s.replace("\\", "\\\\").replace("`", "\\`")
    return f"`{s}`"

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Rename to a valid identifier: letters/underscore first, then alphanumerics/underscores only (e.g. 'my_table').
  2. Sanitize derived names programmatically before passing them (replace invalid chars with '_').
  3. Quote/escape is not offered by this API surface, so renaming is the only path.

Example fix

// before
relation_target(name="my-table", ...)
// after
relation_target(name="my_table", ...)
Defensive patterns

Strategy: validation

Validate before calling

import re
_IDENT = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
def assert_valid_name(name: str) -> None:
    if not _IDENT.match(name):
        raise ValueError(f"invalid SurrealDB identifier: {name!r}")

Type guard

def is_safe_identifier(name: str) -> bool:
    import re
    return bool(re.fullmatch(r"[a-zA-Z_][a-zA-Z0-9_]*", name))

Try / catch

try:
    target = relation_target(name=user_supplied_name, ...)
except ValueError as e:
    if "Invalid SurrealDB" in str(e):
        name = re.sub(r"\W", "_", user_supplied_name)
        target = relation_target(name=name, ...)

Prevention

When it happens

Trigger: Creating a relation_target/table_target or declaring a vector index with a name containing hyphens, dots, spaces, digits at position 0, or other non-identifier characters, e.g. table name 'my-table' or an index named 'idx.embedding'.

Common situations: Deriving table names from file paths or user input ('docs-2024'); using dotted or dashed names common in other databases; generating names programmatically without sanitizing.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/938edfe18618f2f1. Report an issue: GitHub.