infiniflow/ragflow · error · ValueError

Invalid {label} format: {value!r}

Error message

Invalid {label} format: {value!r}

What it means

ValueError from the SQL-injection guard in dialog_service's retrieval query builder: doc_ids/kb_ids values (and other interpolated identifiers) must parse as UUIDs, with the single sentinel '-999' allowed for doc_id. Non-UUID input is logged as a rejected injection attempt and rejected before table-name/WHERE interpolation.

Source

Thrown at api/db/services/dialog_service.py:1032

    """
    logging.debug(f"use_sql: Question: {question}")

    # Determine which document engine we're using
    if settings.DOC_ENGINE_INFINITY:
        doc_engine = "infinity"
    elif settings.DOC_ENGINE_OCEANBASE:
        doc_engine = "oceanbase"
    else:
        doc_engine = "es"

    def _assert_valid_uuid(value: str, label: str = "id") -> None:
        if label == "doc_id" and str(value) == "-999":
            return
        try:
            uuid.UUID(str(value))
        except (ValueError, AttributeError, TypeError):
            logger.warning("SQL injection guard rejected invalid %s value (length=%d)", label, len(str(value)))
            raise ValueError(f"Invalid {label} format: {value!r}")

    if isinstance(doc_ids, str):
        doc_ids = [doc_id for doc_id in doc_ids.split(",") if doc_id]
    else:
        doc_ids = [doc_id for doc_id in doc_ids or [] if doc_id]

    # Construct the full table name
    # For Elasticsearch: ragflow_{tenant_id} (kb_id is in WHERE clause)
    # For Infinity: ragflow_{tenant_id}_{kb_id} (each KB has its own table)
    base_table = index_name(tenant_id)
    if doc_engine == "infinity" and kb_ids and len(kb_ids) == 1:
        # Infinity: append kb_id to table name — validate before interpolating
        _assert_valid_uuid(kb_ids[0], "kb_id")
        table_name = f"{base_table}_{kb_ids[0]}"
        logging.debug(f"use_sql: Using Infinity table name: {table_name}")
    else:
        # Elasticsearch/OpenSearch: use base index name
        table_name = base_table

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Send only real UUIDs for doc_ids/kb_ids (server-generated document and dataset ids).
  2. Use the '-999' sentinel only for the documented doc_id wildcard case.
  3. Filter/validate ids client-side before calling the API (see validationCode).

Example fix

# before
retrieval(doc_ids=["all"])
# after
retrieval(doc_ids=[d.id for d in DocumentService.list_documents(kb_id)])
Defensive patterns

Strategy: validation

Validate before calling

import uuid

def valid_ids(values, allow_sentinel=False):
    out = []
    for v in values or []:
        s = str(v or '').strip()
        if allow_sentinel and s == '-999':
            out.append(s); continue
        uuid.UUID(s)  # raises on anything non-UUID
        out.append(s)
    return out

doc_ids = valid_ids(doc_ids, allow_sentinel=True)
kb_ids = valid_ids(kb_ids)

Type guard

function isUuid(v: unknown): v is string {
  return typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v.trim());
}

Prevention

When it happens

Trigger: Calling retrieval with doc_ids containing arbitrary strings (e.g. "1; DROP TABLE", 'all', or an untrimmed non-UUID id), or a kb_id/tenant_id that is not a UUID — any value passed to _assert_valid_uuid that fails uuid.UUID().

Common situations: Clients using legacy numeric ids or placeholders like 'all'/null coerced to 'None'; test scripts passing raw strings; integrations forwarding user input directly as doc_ids.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/0ea8da8de414bc8e. Report an issue: GitHub.