infiniflow/ragflow · error · GroupValidationError

A template group must contain at least one template.

Error message

A template group must contain at least one template.

What it means

GroupValidationError (a ValueError subclass) raised by _derive_scope in the compilation template group service when the templates list passed to group creation/update is empty. A group's scope is derived from its children (one wiki child => dataset scope, otherwise file scope), so zero children cannot derive any scope and is rejected before persistence.

Source

Thrown at api/db/services/compilation_template_group_service.py:40

from common.misc_utils import get_uuid


SCOPE_FILE = "file"
SCOPE_DATASET = "dataset"


class GroupValidationError(ValueError):
    pass


def _derive_scope(templates: list[dict]) -> str:
    """Derive the group's scope from its child templates.

    One artifacts child = dataset scope (and must be the only child).
    Otherwise file scope, with no artifacts allowed.
    """
    if not templates:
        raise GroupValidationError("A template group must contain at least one template.")
    kinds = [str((t or {}).get("kind") or "").strip() for t in templates]
    artifact_count = sum(1 for k in kinds if k == "wiki")
    if artifact_count > 0:
        if artifact_count != 1 or len(templates) != 1:
            raise GroupValidationError("A wiki template cannot be combined with other templates in the same group.")
        return SCOPE_DATASET

    _enforce_single_rechunk_tree(templates)
    return SCOPE_FILE


def _enforce_single_rechunk_tree(templates: list[dict]) -> None:
    """At most one tree-kind child in the group may enable re-chunking.

    Re-chunking soft-deletes the doc's original chunks via
    ``available_int=0`` and inserts merged replacements; running two
    such templates would race on the same source chunks and produce
    non-deterministic output. Per-tenant invariant is enforced

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Include at least one template (kind 'wiki' alone for dataset scope, or file-scope kinds) in the group payload.
  2. Validate templates is a non-empty array client-side before submitting.
  3. If you meant to remove a group, delete the group instead of emptying it.
  4. Check request-building code for filters that can empty the list.

Example fix

// before
await api.createTemplateGroup({ name, templates: [] });

// after
if (!templates.length) throw new Error('Select at least one template for the group');
await api.createTemplateGroup({ name, templates });
Defensive patterns

Strategy: validation

Validate before calling

if not templates or not isinstance(templates, list):
    raise ValueError("templates must be a non-empty list")

Type guard

def valid_group_payload(templates) -> bool:
    return isinstance(templates, list) and len(templates) > 0

Try / catch

try:
    create_group(name, templates)
except GroupValidationError as e:
    return bad_request(str(e))  # user-input error, never retry

Prevention

When it happens

Trigger: POST/PUT of a template group whose 'templates' array is empty, null-ish, or filtered to nothing during request processing; deleting all children of a group and saving; payload construction bug that drops the templates field.

Common situations: Frontend form allowing save with no selected templates; bulk imports generating empty groups; API clients sending {"templates": []} to create a placeholder group.

Related errors


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