{"record":{"id":"0218287c8ab2802b","repo":"siyuan-note/siyuan","slug":"binary-files-cannot-be-edited-as-text","errorCode":null,"errorMessage":"binary files cannot be edited as text","messagePattern":"binary files cannot be edited as text","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/util/skill_manage.go","lineNumber":30,"sourceCode":"\t\"io/fs\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"github.com/88250/lute/ast\"\n\t\"github.com/siyuan-note/filelock\"\n)\n\nconst maxManagedSkillSourceSize = 8 * 1024 * 1024\n\nvar skillManagementLock sync.Mutex\n\nvar (\n\tErrSkillBinary   = errors.New(\"binary files cannot be edited as text\")\n\tErrSkillEncoding = errors.New(\"only UTF-8 text files can be edited\")\n\tErrSkillTooLarge = errors.New(\"text files must be at most 8 MiB\")\n)\n\ntype SkillFileRequest struct {\n\tAction   string\n\tPath     string\n\tTarget   string\n\tContent  string\n\tRevision string\n}\n\ntype SkillFileEntry struct {\n\tPath     string\n\tIsDir    bool\n\tEditable bool\n}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/skill_manage.go#L12-L48","documentation":"ErrSkillBinary is a sentinel error in the skill file management layer indicating the file content is not editable plain text: it contains a NUL byte or non-whitespace control characters. It is returned by validateManagedSkillSource (on read and write) and by skillSourceReadOnlyReason mapping, so the editor marks the file read-only instead of round-tripping binary data through a text editor.","triggerScenarios":"Reading or writing a skill file whose content contains \\x00 (via strings.ContainsRune) or control runes other than tab/newline/CR/FF; occurs in ManageSkillFiles read/write/create actions.","commonSituations":"A binary asset (PNG, zip, .so) placed inside a skill directory and opened in the text editor; a script saved with CRLF plus stray control characters; a file corrupted by a bad transfer mode.","solutions":["Do not open or edit this file in the text skill editor — use the file panel to remove/replace it with a text version","Strip control characters/NUL bytes if the file is genuinely text (e.g. tr -d '\\000')","Move binary assets outside files intended for text editing"],"exampleFix":"// before\ncontent contains \"\\x00\" -> util.ErrSkillBinary\n\n// after\nsanitized := strings.Map(func(r rune) rune {\n    if unicode.IsControl(r) && r != '\\t' && r != '\\n' && r != '\\r' && r != '\\f' {\n        return -1\n    }\n    return r\n}, content)\n","handlingStrategy":"type-guard","validationCode":"function isEditableText(bytes) {\n  if (bytes.includes(0)) return false;\n  const s = new TextDecoder('utf-8', {fatal: true}).decode(bytes);\n  return ![...s].some(c => {\n    const n = c.codePointAt(0);\n    return n < 32 && n !== 9 && n !== 10 && n !== 13 && n !== 12;\n  });\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.manageSkillFiles({action: 'read', path});\n} catch (e) {\n  if (e.message.includes('binary files cannot be edited')) {\n    // surface file as non-editable in UI\n  }\n}","preventionTips":["Keep binary assets out of text-editable skill files","Check for NUL bytes before writing via API","Normalize line endings and strip control chars on import"],"tags":["binary-file","validation","skill-editor","go"],"backgroundTag":"unsupported-operation","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}