siyuan-note/siyuan · error

Untitled

Error message

Untitled

What it means

validateCreateDoc (kernel/model/file.go:2325) requires the BASENAME of the target path to be a valid tree ID: util.GetTreeID(baseName) must be non-empty, i.e. the file must be named like "20240101120000-abcd123.sy" (14-digit timestamp + 6+ alphanumeric ID). If the base carries no such ID, creation fails with Conf.Language(16). Beware: the English text of Language(16) is "Untitled", which looks like a default-title message but actually means "the path's document ID is missing/malformed" — a frequent misdiagnosis.

Solutions

  1. Generate the path in SiYuan ID form: /<parent>/<yyyyMMddHHmmss>-<random6+.sy, e.g. 20260101120000-a1b2c3d.sy
  2. In Go use the same generator as the kernel (util time + random ID helpers); in JS build it manually from a 14-digit UTC-local timestamp plus 6 random [0-9a-z] chars
  3. If the parent folder is the notebook root, path is "/<id>.sy"; for a sub-doc use "/<parentID>/<childID>.sy" where parentID matches the existing parent document ID

Example fix

// before
fetchPost('/api/filetree/createDocWithMd', {notebook, path: '/my-note.sy', markdown}) // "Untitled" error

// after
const ts = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14)
const rand = Math.random().toString(36).slice(2, 9)
fetchPost('/api/filetree/createDocWithMd', {notebook, path: `/${ts}-${rand}.sy`, markdown})
Defensive patterns

Strategy: validation

Validate before calling

// Verify the basename carries a SiYuan tree ID before creating
func pathHasTreeID(p string) bool {
	return "" != util.GetTreeID(strings.TrimSpace(path.Base(p)))
}

Type guard

func isValidCreatePath(p string) bool {
	base := strings.TrimSpace(path.Base(p))
	return "" != util.GetTreeID(base) && !strings.HasPrefix(base, ".")
}

Prevention

When it happens

Trigger: POST /api/filetree/createDocWithMd with path="/notes/mypage.sy" or "/notes/mypage" (no ID component); any createDoc call where the client supplied a human filename instead of a generated <time><rand> ID. Note a bare "/x.sy" also trips this before the hidden-file check.

Common situations: New API users assuming slug-style paths like normal note apps; converting external filenames to SiYuan paths without an ID step; docs/examples that show path as freeform.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/d5c2a8ad2e272d90. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/file.go:2325

func validateCreateDoc(boxID, p, title string, titleEmpty bool) (ret *createDocValidation, err error) {
	p = normalizeBoxDocPath(boxID, p)
	title = normalizeDocTitle(title)
	if 512 < utf8.RuneCountInString(title) {
		// 限制笔记本名和文档名最大长度为 `512` https://github.com/siyuan-note/siyuan/issues/6299
		return nil, errors.New(Conf.Language(106))
	}

	isEmpty := false
	if "" == title {
		title = Conf.Language(16)
		isEmpty = true
	} else if titleEmpty {
		isEmpty = true
	}

	baseName := strings.TrimSpace(path.Base(p))
	if "" == util.GetTreeID(baseName) {
		return nil, errors.New(Conf.Language(16))
	}
	if strings.HasPrefix(baseName, ".") {
		return nil, errors.New(Conf.Language(13))
	}

	box, boxErr := getOpenedBox(boxID)
	if nil != boxErr {
		return nil, boxErr
	}

	folder := path.Dir(p)
	hPath := "/" + title
	if "/" != folder {
		parentID := path.Base(folder)
		parentTree, loadErr := LoadTreeByBlockID(parentID)
		if nil != loadErr {
			logging.LogErrorf("get parent tree [%s] failed", parentID)
			return nil, ErrBlockNotFound

View on GitHub (pinned to afa823b6b4)