{"record":{"id":"6cf81123e5a5a233","repo":"bytedance/deer-flow","slug":"skill-file-not-found-skill-file-path","errorCode":null,"errorMessage":"Skill file not found: {skill_file_path}","messagePattern":"Skill file not found: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"backend/app/gateway/routers/artifacts.py","lineNumber":277,"sourceCode":"                    return _read_skill_archive_member(zip_ref, info)\n\n            # Not found\n            return None\n    except (zipfile.BadZipFile, KeyError):\n        return None\n\n\ndef _load_skill_archive_member(actual_skill_path: Path, skill_file_path: str, internal_path: str) -> tuple[bytes, str | None]:\n    \"\"\"Worker-thread body for the ``.skill`` branch of ``get_artifact``.\n\n    The ``exists`` / ``is_file`` probes, the ZIP open+extract, and the MIME\n    sniff (``mimetypes`` lazily stats the system MIME database on first use) are\n    blocking filesystem IO and must stay off the event loop. Raised\n    ``HTTPException``s propagate through ``asyncio.to_thread`` unchanged,\n    preserving status codes.\n    \"\"\"\n    if not actual_skill_path.exists():\n        raise HTTPException(status_code=404, detail=f\"Skill file not found: {skill_file_path}\")\n    if not actual_skill_path.is_file():\n        raise HTTPException(status_code=400, detail=f\"Path is not a file: {skill_file_path}\")\n    content = _extract_file_from_skill_archive(actual_skill_path, internal_path)\n    if content is None:\n        raise HTTPException(status_code=404, detail=f\"File '{internal_path}' not found in skill archive\")\n    mime_type, _ = mimetypes.guess_type(internal_path)\n    return content, mime_type\n\n\ndef _read_artifact_payload(actual_path: Path, path: str, download: bool) -> tuple[str, str | None]:\n    \"\"\"Worker-thread body for the regular branch of ``get_artifact``.\n\n    Stat probes and MIME sniffing (``mimetypes`` lazily stats the system MIME\n    database on first use) are blocking filesystem IO. Returns a\n    ``(kind, mime_type)`` plan the handler turns into a streamed\n    ``FileResponse``. Inline text and binary previews both use FileResponse so\n    clients can request a bounded byte range instead of buffering a whole file.\n    \"\"\"","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/artifacts.py#L259-L295","documentation":"HTTP 404 from _load_skill_archive_member (worker thread of GET artifact): the .skill file itself does not exist at the resolved path (actual_skill_path.exists() is False). The archive-level check runs before any member lookup — the whole pack is gone, distinct from a missing internal member.","triggerScenarios":"GET /api/threads/{thread_id}/artifacts for a .skill path (e.g. 'mnt/user-data/outputs/x.skill#SKILL.md') where the .skill file was deleted or never written to outputs.","commonSituations":"Previewing a skill pack referenced from stale thread state after the run regenerated outputs, deleted packs, or paths built from old listings.","solutions":["Re-list the thread's artifacts to see whether the .skill file still exists under its actual name","If the pack should exist, re-run the step that produces/installs it into outputs","Handle 404 by clearing the preview rather than retrying"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef skill_archive_exists(actual_skill_path: str) -> bool:\n    return Path(actual_skill_path).exists()","typeGuard":null,"tryCatchPattern":"if resp.status_code == 404 and \"Skill file not found\" in resp.text:\n    clear_preview(); refresh_artifact_list()","preventionTips":["Refresh listings after runs that rewrite outputs before offering skill previews","Distinguish this 404 (whole archive missing) from the internal-member 404 by detail text","Avoid caching .skill artifact paths across runs"],"tags":["api","artifacts","skills","not-found","http-404"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}