HKUDS/DeepTutor · error · GenerationFailure

no questions generated

Error message

no questions generated

What it means

Even though QuizGenerator succeeded, the block's _extract_questions(summary) extracted zero usable questions from the returned summary dict — either the summary lacked question data or every question failed extraction. The guard then raises GenerationFailure('no questions generated').

Source

Thrown at deeptutor/book/blocks/quiz.py:72

                    user_message=topic,
                    active_capability="deep_question",
                    knowledge_bases=[effective_kb] if effective_kb else [],
                    language=ctx.language,
                ),
                user_message=topic,
                num_questions=max(1, int(num_questions or 1)),
                difficulty=difficulty,
                question_types=question_types,
                stream=get_book_bus(ctx.book_id),
            )
            summary = dict(result.get("summary") or {})
        except Exception as exc:
            logger.warning(f"QuizGenerator failed: {exc}", exc_info=True)
            raise GenerationFailure(f"quiz generation failed: {exc}") from exc

        questions = self._extract_questions(summary)
        if not questions:
            raise GenerationFailure("no questions generated")

        return (
            {"questions": questions, "topic": topic},
            [],
            {
                "completed": summary.get("completed", 0),
                "failed": summary.get("failed", 0),
                "kb": ctx.primary_kb,
            },
        )

    @staticmethod
    def _extract_questions(summary: dict[str, Any]) -> list[dict[str, Any]]:
        results = summary.get("results") or []
        if not isinstance(results, list):
            return []
        out: list[dict[str, Any]] = []
        for item in results:

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Log the summary dict and compare its question structure against _extract_questions' expectations
  2. Align the QuizGenerator version with the block, or update the extractor key/shape handling
  3. Retry with clearer quiz parameters (non-empty question_types)
  4. If the generator legitimately produced no questions, prompt for at least N questions
Defensive patterns

Strategy: validation

Validate before calling

summary = result.get('summary') or {}
qs = summary.get('questions') or []
assert qs, 'quiz summary has no questions; aborting before block guard'

Type guard

def summary_has_questions(summary: dict) -> bool:
    return isinstance(summary, dict) and isinstance(summary.get('questions'), list) and len(summary['questions']) > 0

Try / catch

try:
    return await quiz_block.generate(ctx)
except GenerationFailure as exc:
    if 'no questions generated' in str(exc):
        return await quiz_block.generate(ctx)  # retry once
    raise

Prevention

When it happens

Trigger: Calling quiz _generate when result['summary'] is empty/None (generator returned dict without questions) or its question entries don't match the shape _extract_questions expects, yielding an empty list.

Common situations: QuizGenerator returns summary with questions under a different key after a version change; questions stored as non-dict entries that extraction skips; LLM produced no questions but the generator didn't fail; completed counts present but questions list empty.

Related errors


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