HKUDS/DeepTutor · error · GenerationFailure

SectionArchitect produced no subsections in outline pass.

Error message

SectionArchitect produced no subsections in outline pass.

What it means

The section block runs a two-pass flow: SectionArchitect first produces an outline dict, and pass 2 fills subsections. If outline.get('subsections') is empty/missing, the outline pass failed to deliver structure and GenerationFailure is raised before any content generation.

Source

Thrown at deeptutor/book/blocks/section.py:103

        # when the cached sweep returned nothing.
        rag = await optional_rag_lookup(
            query=f"{chapter_title}: {focus_topic}",
            ctx=ctx,
        )

        # ── Pass 1: outline ───────────────────────────────────────────
        outline = await self._make_outline(
            ctx=ctx,
            chapter_title=chapter_title,
            chapter_summary=chapter_summary,
            objectives=objectives,
            focus_topic=focus_topic,
            section_role=section_role,
            target_words=target_words,
            rag_context=rag.text,
        )
        if not outline.get("subsections"):
            raise GenerationFailure("SectionArchitect produced no subsections in outline pass.")

        # ── Pass 2: fill subsections in parallel ─────────────────────
        relevant_chunks: list[SourceChunk] = []
        try:
            relevant_chunks = ctx.relevant_chunks(focus_topic, limit=8)
        except Exception:  # noqa: BLE001
            relevant_chunks = []

        subs = outline["subsections"]
        coros = [
            self._fill_subsection(
                ctx=ctx,
                chapter_title=chapter_title,
                section_focus=focus_topic,
                outline_intro=outline.get("intro", ""),
                sub=sub,
                chunks=relevant_chunks,
            )

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Log the raw outline payload to see whether subsections is absent, empty, or under another key
  2. Retry — outline omissions are often transient
  3. Tighten the architect prompt to enforce the exact JSON schema with a minimum subsection count
  4. Use a stronger model and ensure focus_topic/target_words/section_role inputs are sane
Defensive patterns

Strategy: retry

Type guard

def outline_has_subsections(outline) -> bool:
    return isinstance(outline, dict) and isinstance(outline.get('subsections'), list) and len(outline['subsections']) > 0

Try / catch

try:
    return await section_block.generate(ctx)
except GenerationFailure as exc:
    if 'no subsections' in str(exc):
        return await section_block.generate(ctx)  # outline passes are flaky
    raise

Prevention

When it happens

Trigger: Calling section _generate when SectionArchitect returns an outline without a 'subsections' key, with an empty list, or a payload where subsections parses to nothing (e.g. outline is a refusal string parsed to {}).

Common situations: LLM returns JSON missing 'subsections' due to prompt/schema drift; subsections under a different key ('sections'); overly constrained target_words or odd section_role confusing the architect; model too weak to follow the outline schema; rag_context empty leading to degenerate outline.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/ba319c5b8257f811. Report an issue: GitHub.