{"record":{"id":"bb9e93f92a9f8139","repo":"odysseus-dev/odysseus","slug":"expected-a-directory-on-github","errorCode":null,"errorMessage":"expected a directory on GitHub","messagePattern":"expected a directory on GitHub","errorType":"validation","errorClass":"SkillImportError","httpStatus":null,"severity":"error","filePath":"services/memory/skill_importer.py","lineNumber":407,"sourceCode":"def _fetch_text(url: str) -> str:\n    data = _fetch_bytes(url)\n    try:\n        return data.decode(\"utf-8\")\n    except UnicodeDecodeError as e:\n        raise SkillImportError(f\"non-text file: {url}\") from e\n\n\ndef _list_github_dir(src: ResolvedSource, rel_dir: str, out: Dict[str, str], *, depth: int = 0) -> None:\n    if depth > 4 or len(out) >= MAX_FILES:\n        return\n    url = _api_contents_url(src, rel_dir)\n    r = _get_checked(url, headers={\"Accept\": \"application/vnd.github+json\"}, timeout=30.0)\n    if r.status_code >= 400:\n        raise _github_response_error(r)\n    _assert_github_url(str(r.url), context=\"redirect target\")\n    entries = r.json()\n    if not isinstance(entries, list):\n        raise SkillImportError(\"expected a directory on GitHub\")\n    total = sum(len(v.encode(\"utf-8\")) for v in out.values())\n    for ent in entries:\n        if len(out) >= MAX_FILES or total >= MAX_TOTAL_BYTES:\n            break\n        if not isinstance(ent, dict):\n            continue\n        name = ent.get(\"name\") or \"\"\n        ent_type = ent.get(\"type\")\n        rel = _safe_relpath(f\"{rel_dir}/{name}\" if rel_dir else name)\n        if ent_type == \"dir\":\n            _list_github_dir(src, rel, out, depth=depth + 1)\n            total = sum(len(v.encode(\"utf-8\")) for v in out.values())\n            continue\n        if ent_type != \"file\" or not _is_text_file(name):\n            continue\n        dl = ent.get(\"download_url\")\n        if not dl:\n            continue","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/services/memory/skill_importer.py#L389-L425","documentation":"Error \"expected a directory on GitHub\" thrown in odysseus-dev/odysseus.","triggerScenarios":"Triggered when the corresponding server-side validation or runtime check at the recorded location rejects the request or operation and returns this error message to the caller.","commonSituations":"See trigger scenarios.","solutions":["Link to the skill's directory on GitHub, not a single file.","Use the /tree/<branch>/<folder> URL of the skill folder."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}