infiniflow/ragflow · error · GroupValidationError

Each template must include a name, kind, and config object.

Error message

Each template must include a name, kind, and config object.

What it means

GroupValidationError raised during group update when a submitted template entry is missing kind, name, or its config is not a dict. The fields are coerced with str(...).strip(), so empty/whitespace strings and null names or kinds fail, and any non-dict config (list, string, null that defaults to {} is fine) fails the isinstance check.

Source

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

                current_by_id = {child.id: child for child in current_children}
                retained_ids: set[str] = set()
                seen_names: set[str] = set()

                for index, child in enumerate(templates):
                    child_id = str((child or {}).get("id") or "").strip()
                    target = current_by_id.get(child_id) if child_id else None
                    if child_id and target is None:
                        raise GroupValidationError(f"Template {child_id} does not belong to this group.")
                    # Older clients did not send child ids. Preserve their
                    # existing ids by matching the submitted order.
                    if target is None and not child_id and index < len(current_children):
                        target = current_children[index]

                    kind = str((child or {}).get("kind") or "").strip()
                    name = str((child or {}).get("name") or "").strip()
                    config = (child or {}).get("config") or {}
                    if not kind or not name or not isinstance(config, dict):
                        raise GroupValidationError("Each template must include a name, kind, and config object.")
                    if name in seen_names:
                        raise GroupValidationError(f"Template name '{name}' is duplicated in this group.")
                    seen_names.add(name)

                    from api.db.services.compilation_template_service import CompilationTemplateService

                    config = CompilationTemplateService.fill_config_default_llm(config, tenant_id)
                    duplicate_query = CompilationTemplate.select().where(
                        CompilationTemplate.tenant_id == tenant_id,
                        CompilationTemplate.group_id == group_id,
                        CompilationTemplate.name == name,
                        ~CompilationTemplate.is_builtin,
                        CompilationTemplate.status == StatusEnum.VALID.value,
                    )
                    if target is not None:
                        duplicate_query = duplicate_query.where(CompilationTemplate.id != target.id)
                    if duplicate_query.exists():
                        raise GroupValidationError(f"Template name '{name}' already exists. Please choose another name.")

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Ensure every template entry has a non-empty name and kind and config is a JSON object.
  2. Validate the payload shape client-side before the request (see typeGuard below).
  3. Check for accidental double-JSON-encoding of config (config: '"{\"chunk_token_num\":...}"').

Example fix

// before
{"name": "", "kind": "tree", "config": "{}"}
// after
{"name": "My template", "kind": "tree", "config": {}}
Defensive patterns

Strategy: type-guard

Validate before calling

def template_entry_ok(t):
    return (
        isinstance(t, dict)
        and bool(str(t.get('kind') or '').strip())
        and bool(str(t.get('name') or '').strip())
        and isinstance(t.get('config') or {}, dict)
    )

assert all(template_entry_ok(t) for t in payload['templates'])

Type guard

type TemplateEntry = { name: string; kind: string; config: Record<string, unknown> };
function isTemplateEntry(t: unknown): t is TemplateEntry {
  return (
    !!t && typeof t === 'object' &&
    typeof (t as any).name === 'string' && (t as any).name.trim() !== '' &&
    typeof (t as any).kind === 'string' && (t as any).kind.trim() !== '' &&
    typeof (t as any).config === 'object' && (t as any).config !== null && !Array.isArray((t as any).config)
  );
}

Prevention

When it happens

Trigger: Group save payload containing a template with empty name, empty kind, or config as a non-object (e.g. a JSON string or array). Note config:null passes because the code substitutes {}.

Common situations: Form submitted before required fields filled; client sending config as a JSON-encoded string instead of an object; partial template object appended by buggy frontend state management.

Related errors


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