{"record":{"id":"2c21b61f66217f52","repo":"HKUDS/DeepTutor","slug":"conceptanalysisagent-prompts-are-not-configured","errorCode":null,"errorMessage":"ConceptAnalysisAgent prompts are not configured.","messagePattern":"ConceptAnalysisAgent prompts are not configured\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"deeptutor/agents/math_animator/agents/concept_analysis_agent.py","lineNumber":55,"sourceCode":"        style_hint: str,\n        attachments: list[Attachment],\n    ) -> ConceptAnalysis:\n        system_prompt = self.get_prompt(\"system\")\n        user_template = self.get_prompt(\"user_template\")\n        if not system_prompt or not user_template:\n            # Retry once: a worker that looked the prompts up before the\n            # package finished installing used to cache the empty result\n            # forever. PromptManager no longer caches misses, so a reload can\n            # now actually recover — and it stays the one place that knows how\n            # to find a prompt file.\n            self.prompts = get_prompt_manager().reload_prompts(\n                \"math_animator\", \"concept_analysis_agent\", self.language\n            )\n            system_prompt = self.get_prompt(\"system\")\n            user_template = self.get_prompt(\"user_template\")\n\n        if not system_prompt or not user_template:\n            raise ValueError(\"ConceptAnalysisAgent prompts are not configured.\")\n\n        reference_count = sum(1 for item in attachments if item.type == \"image\")\n        user_prompt = user_template.format(\n            user_input=user_input.strip(),\n            history_context=history_context.strip() or \"(none)\",\n            output_mode=output_mode,\n            style_hint=style_hint.strip() or \"(none)\",\n            reference_count=reference_count,\n        )\n        messages = [\n            {\"role\": \"system\", \"content\": system_prompt},\n            {\"role\": \"user\", \"content\": user_prompt},\n        ]\n        _chunks: list[str] = []\n        async for _c in self.stream_llm(\n            user_prompt=user_prompt,\n            system_prompt=system_prompt,\n            messages=messages,","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/agents/math_animator/agents/concept_analysis_agent.py#L37-L73","documentation":"Raised when pypdf raises FileNotDecryptedError while reading pages of an encrypted PDF whose is_encrypted flag did not already trip the earlier check (e.g. a PDF decrypted with a wrong/owner password where page access still fails). The original exception is chained and wrapped in CorruptDocumentError.","triggerScenarios":"pypdf opens the file but page.extract_text() raises FileNotDecryptedError on an encrypted PDF where is_encrypted was false or decrypt partially succeeded.","commonSituations":"Edge-case encrypted PDFs (owner-password-only, broken encryption dictionaries) in ingestion pipelines; version drift in pypdf changing when FileNotDecryptedError is emitted.","solutions":["Decrypt properly with pikepdf/qpdf upstream","Upgrade pypdf — decryption behavior has changed across versions","Fall back to pymupdf (install it), which handles more encryption edge cases"],"exampleFix":"// before\ntext = extract_text_from_bytes(data, filename=\"weird.pdf\")\n\n// after\nimport pikepdf, io\nwith pikepdf.open(io.BytesIO(data)) as pdf:  # normalizes encryption edge cases\n    buf = io.BytesIO(); pdf.save(buf)\ntext = extract_text_from_bytes(buf.getvalue(), filename=\"weird.pdf\")","handlingStrategy":"fallback","validationCode":"import pikepdf, io\n\ndef normalize_pdf(data: bytes) -> bytes:\n    try:\n        with pikepdf.open(io.BytesIO(data)) as pdf:\n            buf = io.BytesIO(); pdf.save(buf); return buf.getvalue()\n    except pikepdf.PasswordError:\n        raise ValueError(\"password required\")\n    except Exception:\n        return data","typeGuard":null,"tryCatchPattern":"except CorruptDocumentError as e:\n    if \"encrypted\" in str(e):\n        data2 = normalize_pdf(data)  # best-effort repair\n        text = extract_text_from_bytes(data2, filename=fn)","preventionTips":["Normalize PDFs through pikepdf during pre-ingest","Pin pypdf versions and test on encrypted samples in CI"],"tags":["pdf","encryption","pypdf","edge-case"],"backgroundTag":"encrypted-pdf-password","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}