{"record":{"id":"284502e1d9ca1119","repo":"conductor-oss/conductor","slug":"skill-file-must-be-utf-8-text-path","errorCode":null,"errorMessage":"Skill file must be UTF-8 text: {path}","messagePattern":"Skill file must be UTF-8 text: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java","lineNumber":597,"sourceCode":"            return MAPPER.convertValue(map, MAP_TYPE);\n        } catch (IllegalArgumentException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new IllegalArgumentException(\n                    \"Invalid SKILL.md frontmatter: \" + e.getMessage(), e);\n        }\n    }\n\n    private String decodeUtf8(String path, byte[] data) {\n        try {\n            return StandardCharsets.UTF_8\n                    .newDecoder()\n                    .onMalformedInput(CodingErrorAction.REPORT)\n                    .onUnmappableCharacter(CodingErrorAction.REPORT)\n                    .decode(ByteBuffer.wrap(data))\n                    .toString();\n        } catch (CharacterCodingException e) {\n            throw new IllegalArgumentException(\"Skill file must be UTF-8 text: \" + path, e);\n        }\n    }\n\n    private boolean isRootAgentFile(String path) {\n        return !path.contains(\"/\") && path.endsWith(\"-agent.md\");\n    }\n\n    private boolean isScriptFile(String path) {\n        if (!path.startsWith(\"scripts/\")) {\n            return false;\n        }\n        String filename = path.substring(\"scripts/\".length());\n        return !filename.isBlank() && !filename.contains(\"/\");\n    }\n\n    private boolean isResourceFile(String path) {\n        if (!path.contains(\"/\")) {\n            return true;","sourceCodeStart":579,"sourceCodeEnd":615,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java#L579-L615","documentation":"Thrown by decodeUtf8 when a file inside an uploaded skill package cannot be decoded as UTF-8. The decoder is configured with CodingErrorAction.REPORT for both malformed and unmappable sequences, so any byte sequence that is not valid UTF-8 (e.g. a Windows-1252 smart quote, a Latin-1 byte, or a binary asset mislabeled as text) causes the failure.","triggerScenarios":"A package entry whose extension is in TEXT_EXTENSIONS (.md/.txt/.json/.yaml/.yml/...) contains non-UTF-8 bytes, or a binary file was renamed to a text extension. decodeUtf8 is invoked on it and the CharsetDecoder throws CharacterCodingException.","commonSituations":"Markdown authored on Windows saved as CP1252; a PNG or PDF slipped in with a `.txt` extension; a JSON file saved with a BOM or mojibake from a previous encoding round-trip.","solutions":["Re-save the offending file as UTF-8 without BOM (`iconv -f CP1252 -t UTF-8 file.md`).","Double-check the file is actually text — if it is binary, give it a binary extension so it is not routed through decodeUtf8.","Strip BOM bytes (`sed -i '1s/^\\xEF\\xBB\\xBF//' file.md`)."],"exampleFix":"// before: SKILL.md saved as Windows-1252 with smart quotes\n// convert on the command line\niconv -f CP1252 -t UTF-8 SKILL.md -o SKILL.md.utf8 && mv SKILL.md.utf8 SKILL.md","handlingStrategy":"validation","validationCode":"// Reject non-UTF-8 text entries before packaging.\nprivate static void assertUtf8(String path, byte[] bytes) {\n    try {\n        StandardCharsets.UTF_8.newDecoder()\n            .onMalformedInput(CodingErrorAction.REPORT)\n            .onUnmappableCharacter(CodingErrorAction.REPORT)\n            .decode(ByteBuffer.wrap(bytes));\n    } catch (CharacterCodingException e) {\n        throw new IllegalArgumentException(path + \" is not UTF-8\", e);\n    }\n}","typeGuard":"boolean isUtf8(byte[] bytes) {\n    try {\n        StandardCharsets.UTF_8.newDecoder()\n            .onMalformedInput(CodingErrorAction.REPORT)\n            .onUnmappableCharacter(CodingErrorAction.REPORT)\n            .decode(ByteBuffer.wrap(bytes));\n        return true;\n    } catch (CharacterCodingException e) { return false; }\n}","tryCatchPattern":"try {\n    return skillRegistry.readFile(skillId, path);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"UTF-8\")) return unsupportedMediaType(e.getMessage());\n    throw e;\n}","preventionTips":["Save all skill text files as UTF-8 without BOM.","Run `file -I <path>` in CI and assert charset is utf-8 for text extensions.","Do not rename binary files to text extensions."],"tags":["skill-registry","encoding","utf-8","validation"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}