siyuan-note/siyuan · warning

binary files cannot be edited as text

Error message

binary files cannot be edited as text

What it means

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.

Solutions

  1. Do not open or edit this file in the text skill editor — use the file panel to remove/replace it with a text version
  2. Strip control characters/NUL bytes if the file is genuinely text (e.g. tr -d '\000')
  3. Move binary assets outside files intended for text editing

Example fix

// before
content contains "\x00" -> util.ErrSkillBinary

// after
sanitized := strings.Map(func(r rune) rune {
    if unicode.IsControl(r) && r != '\t' && r != '\n' && r != '\r' && r != '\f' {
        return -1
    }
    return r
}, content)
Defensive patterns

Strategy: type-guard

Validate before calling

function isEditableText(bytes) {
  if (bytes.includes(0)) return false;
  const s = new TextDecoder('utf-8', {fatal: true}).decode(bytes);
  return ![...s].some(c => {
    const n = c.codePointAt(0);
    return n < 32 && n !== 9 && n !== 10 && n !== 13 && n !== 12;
  });
}

Try / catch

try {
  await api.manageSkillFiles({action: 'read', path});
} catch (e) {
  if (e.message.includes('binary files cannot be edited')) {
    // surface file as non-editable in UI
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/0218287c8ab2802b. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/skill_manage.go:30

	"io/fs"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"unicode"
	"unicode/utf8"

	"github.com/88250/lute/ast"
	"github.com/siyuan-note/filelock"
)

const maxManagedSkillSourceSize = 8 * 1024 * 1024

var skillManagementLock sync.Mutex

var (
	ErrSkillBinary   = errors.New("binary files cannot be edited as text")
	ErrSkillEncoding = errors.New("only UTF-8 text files can be edited")
	ErrSkillTooLarge = errors.New("text files must be at most 8 MiB")
)

type SkillFileRequest struct {
	Action   string
	Path     string
	Target   string
	Content  string
	Revision string
}

type SkillFileEntry struct {
	Path     string
	IsDir    bool
	Editable bool
}

View on GitHub (pinned to 9f775e8a12)