{"record":{"id":"775bd37119584324","repo":"iflytek/astron-agent","slug":"skill-resource-is-unavailable","errorCode":null,"errorMessage":"Skill resource is unavailable","messagePattern":"Skill resource is unavailable","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"core/agent/service/plugin/skill.py","lineNumber":250,"sourceCode":"                }\n                return PluginResponse(result=result)\n\n        return _runner\n\n    def _normalize_path(self, value: Any) -> str:\n        path = str(value or \"\").strip().replace(\"\\\\\", \"/\")\n        while path.startswith(\"./\"):\n            path = path[2:]\n        return path.lstrip(\"/\")\n\n    async def _download_text(self, url: str) -> str:\n        timeout = aiohttp.ClientTimeout(total=30)\n        async with aiohttp.ClientSession(timeout=timeout) as session:\n            value = await download_skill_resource(session, url, MAX_SKILL_TEXT_BYTES)\n        try:\n            return value.decode(\"utf-8\", errors=\"strict\")\n        except UnicodeDecodeError:\n            raise RuntimeError(SKILL_RESOURCE_ERROR) from None\n","sourceCodeStart":232,"sourceCodeEnd":251,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/agent/service/plugin/skill.py#L232-L251","documentation":"RuntimeError(SKILL_RESOURCE_ERROR) ('Skill resource is unavailable') raised in SkillPlugin._download_text (skill.py:250). The skill resource was downloaded within the byte limit, but its bytes are not valid UTF-8, so decoding with errors='strict' raises UnicodeDecodeError, which is converted into this user-facing error. It protects downstream consumers (LLM prompts, sandbox) from binary garbage masquerading as skill text.","triggerScenarios":"Downloading a skill resource whose download_url points to a binary file (zip, pdf, image, or non-UTF-8 encoded text) instead of UTF-8 text, then attempting decode.","commonSituations":"Skill author uploaded a binary asset or a file saved with a non-UTF-8 encoding (GBK, UTF-16, Latin-1), or the URL redirects to an error page/CDN binary response instead of the text resource.","solutions":["Re-upload the skill resource as a UTF-8 text file (convert encoding, e.g. iconv -f GBK -t UTF-8).","Verify the download_url actually points to the text file and not a binary or HTML error page; fetch it and run `file` on it.","Only mark text-decodable files as downloadable skill resources; exclude binaries at skill-publish time.","If the content is legitimately non-text, serve it as a sandbox file resource rather than inline skill text."],"exampleFix":"// before\nvalue = await download_skill_resource(session, url, MAX_SKILL_TEXT_BYTES)\nreturn value.decode(\"utf-8\", errors=\"strict\")\n// after: tolerate BOM / pick a fallback before failing\nvalue = await download_skill_resource(session, url, MAX_SKILL_TEXT_BYTES)\nif value.startswith(codecs.BOM_UTF8):\n    value = value[len(codecs.BOM_UTF8):]\ntry:\n    return value.decode(\"utf-8\")\nexcept UnicodeDecodeError:\n    return value.decode(\"utf-8\", errors=\"replace\")","handlingStrategy":"validation","validationCode":"def is_valid_utf8(data: bytes) -> bool:\n    try:\n        data.decode(\"utf-8\")\n        return True\n    except UnicodeDecodeError:\n        return False\n# call before treating the download as skill text\nif not is_valid_utf8(value):\n    raise RuntimeError(SKILL_RESOURCE_ERROR)","typeGuard":"def looks_like_text(data: bytes) -> bool:\n    text_chars = bytes(range(32, 127)) + b\"\\n\\r\\t\"\n    return not bool(data.translate(None, delete=text_chars))","tryCatchPattern":"try:\n    text = await plugin._download_text(url)\nexcept RuntimeError as e:\n    if str(e) == SKILL_RESOURCE_ERROR:\n        logger.warning(\"skill resource %s is not valid UTF-8 text; skipping\", url)\n    raise","preventionTips":["Publish skill resources only as UTF-8-encoded text files","Reject binary uploads at skill-publish time using a magic-byte check","Verify download_urls resolve to the actual text file, not redirects or error pages","Strip BOM and normalize encodings when importing skills"],"tags":["skill","encoding","download","utf-8"],"backgroundTag":"invalid-argument-format","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}