{"record":{"id":"6bc59430e579aafc","repo":"HKUDS/DeepTutor","slug":"llm-did-not-return-any-flashcards","errorCode":null,"errorMessage":"LLM did not return any flashcards.","messagePattern":"LLM did not return any flashcards\\.","errorType":"exception","errorClass":"GenerationFailure","httpStatus":null,"severity":"error","filePath":"deeptutor/book/blocks/flash_cards.py","lineNumber":65,"sourceCode":"        cards_raw = data.get(\"cards\") if isinstance(data, dict) else None\n        cards: list[dict[str, str]] = []\n        if isinstance(cards_raw, list):\n            for item in cards_raw[:count]:\n                if not isinstance(item, dict):\n                    continue\n                front = str(item.get(\"front\") or \"\").strip()\n                back = str(item.get(\"back\") or \"\").strip()\n                if not front or not back:\n                    continue\n                cards.append(\n                    {\n                        \"front\": front[:300],\n                        \"back\": back[:600],\n                        \"hint\": str(item.get(\"hint\") or \"\").strip()[:200],\n                    }\n                )\n        if not cards:\n            raise GenerationFailure(\"LLM did not return any flashcards.\")\n        return (\n            {\"cards\": cards},\n            [],\n            data.get(\"_metadata\") if isinstance(data.get(\"_metadata\"), dict) else {},\n        )\n\n\n__all__ = [\"FlashCardsGenerator\"]\n","sourceCodeStart":47,"sourceCodeEnd":74,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/book/blocks/flash_cards.py#L47-L74","documentation":"The flash_cards block parses the LLM response into flashcards (front/back/hint); if zero cards survive extraction, it raises GenerationFailure. This happens when the LLM returns no items, or every item lacks usable front/back text.","triggerScenarios":"Calling flash_cards _generate when the LLM response has an empty cards list, non-conforming JSON where items have blank front/back fields, or a refusal message that parses to nothing.","commonSituations":"Prompt drift so the model returns a different JSON shape; items filtered out because front/back were empty strings after strip(); weak model producing refusals; truncated JSON from token limits producing zero parsed items.","solutions":["Retry once — empty LLM outputs are frequently transient","Log the raw LLM payload to see whether cards were absent or dropped during parsing","Constrain the prompt with an explicit JSON schema and a minimum card count","Switch to a model with reliable JSON/structured output (or enable structured output mode if available)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    return await flash_cards_block.generate(ctx)\nexcept GenerationFailure as exc:\n    if 'did not return any flashcards' in str(exc):\n        return await flash_cards_block.generate(ctx)  # one retry\n    raise","preventionTips":["Require a minimum card count in the prompt with an explicit JSON schema","Use a model with reliable JSON output","Log raw responses on empty parses to catch schema drift"],"tags":["flashcards","llm-output","empty-response","generation"],"backgroundTag":"llm-empty-response","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}