siyuan-note/siyuan · error
344
344
Error message
Markdown [%s] is not valid UTF-8
What it means
A Markdown file's bytes are not valid UTF-8, so the importer refuses to process it (error code 344). SiYuan stores note content as UTF-8 text; importing non-UTF-8 bytes would corrupt block content, so the offending file is reported with its vault-relative path and the import of that document fails.
Solutions
- Re-encode the reported file to UTF-8 (iconv -f GBK -t UTF-8 file.md, or VS Code 'Save with Encoding → UTF-8')
- Detect the actual encoding with file/chardet before converting
- If the file is UTF-16 with BOM, convert to UTF-8 explicitly
- Exclude or delete the non-text file if it is not a real note
Example fix
$ iconv -f GB18030 -t UTF-8 notes/old.md > notes/old.utf8.md $ mv notes/old.utf8.md notes/old.md
Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
const buf = fs.readFileSync(mdFile);
const decoded = new TextDecoder('utf-8', { fatal: true }).decode(buf); // throws on invalid UTF-8 Prevention
- Convert legacy-encoded notes (GBK, Latin-1, UTF-16) to UTF-8 before import
- Run a bulk check (e.g. isutf8 from moreutils) across the vault
- Avoid creating .md files via PowerShell redirection (produces UTF-16)
When it happens
Trigger: readStableObsidianFile returns bytes for a `.md` source and utf8.Valid(data) is false — the file contains legacy encodings (GBK, Latin-1, UTF-16) or binary junk.
Common situations: Old notes created with Windows editors in a legacy codepage; files converted from Evernote/Word without re-encoding; UTF-16 files produced by PowerShell redirection; a `.md` file that is actually binary.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- 347
- invalid template source
- only UTF-8 text files can be edited
- skill resource is not valid UTF-8
- template source is not UTF-8
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/e23dc87a05cc9819.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/import_obsidian.go:862
}
func analyzeObsidianDocuments(ctx context.Context, vault *obsidianVaultContext, progress func(int, string)) error {
sourceCount := countObsidianSourceDocs(vault.Docs)
processed := 0
for _, doc := range vault.Docs {
if doc.Synthetic {
continue
}
if err := ctx.Err(); err != nil {
return err
}
data, err := readStableObsidianFile(doc.Source)
if err != nil {
return newObsidianReadUserError(doc.Source, err)
}
if !utf8.Valid(data) {
return newObsidianUserError(344, doc.Source.RelPath,
fmt.Errorf("Markdown [%s] is not valid UTF-8", doc.Source.RelPath))
}
scan := scanObsidianSource(data)
for _, blockID := range scan.BlockIDs {
if scan.Duplicates[blockID] {
doc.DuplicateBlocks[blockID] = true
}
if doc.BlockIDs[blockID] == "" {
doc.BlockIDs[blockID] = ast.NewNodeID()
}
}
tree, _, _, _ := parseStdMd(data)
if tree == nil {
return newObsidianUserError(347, doc.Source.RelPath,
fmt.Errorf("parse Markdown [%s] failed", doc.Source.RelPath))
}
buildObsidianHeadingIndex(doc, tree)
vault.Analysis.WikiLinkCount += countObsidianNonEmbedTokens(scan.Wikis)
vault.Analysis.EmbedCount += countObsidianEmbedTokens(scan.Wikis)View on GitHub (pinned to 9f775e8a12)