{"record":{"id":"61e6dda3e4ed36a2","repo":"siyuan-note/siyuan","slug":"do-not-include-markdown-syntax-marker-s","errorCode":null,"errorMessage":"Do not include Markdown syntax marker [%s]","messagePattern":"Do not include Markdown syntax marker \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/bookmark.go","lineNumber":98,"sourceCode":"\t\t\tif err = writeTreeUpsertQueue(tree); err != nil {\n\t\t\t\tutil.ClearPushProgress(100)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tutil.RandomSleep(50, 150)\n\t}\n\n\tindexHistoryDir(filepath.Base(historyDir), util.NewLute())\n\tsql.FlushQueue()\n\n\tutil.ReloadUI()\n\treturn\n}\n\nfunc RenameBookmark(oldBookmark, newBookmark string) (err error) {\n\tif invalidChar := treenode.ContainsMarker(newBookmark); \"\" != invalidChar {\n\t\treturn fmt.Errorf(Conf.Language(112), invalidChar)\n\t}\n\n\tnewBookmark = strings.TrimSpace(newBookmark)\n\tif \"\" == newBookmark {\n\t\treturn errors.New(Conf.Language(126))\n\t}\n\n\tif oldBookmark == newBookmark {\n\t\treturn\n\t}\n\n\tutil.PushEndlessProgress(Conf.Language(110))\n\tdefer util.ClearPushProgress(100)\n\n\tbookmarks := sql.QueryBookmarkBlocks()\n\ttreeBlocks := map[string][]string{}\n\tfor _, bm := range bookmarks {\n\t\tif blocks, ok := treeBlocks[bm.RootID]; !ok {","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/bookmark.go#L80-L116","documentation":"In RenameBookmark (bookmark.go:96) the very first check runs treenode.ContainsMarker(newBookmark); if it returns a non-empty char, the function returns fmt.Errorf(Conf.Language(112), invalidChar) — 'Do not include Markdown syntax marker [%s]'. Bookmark names are stored in block IAL and feed the bookmark panel, so characters that double as Markdown/Kramdown syntax markers (#, *, >, -, +, =, ~, `, etc.) are forbidden to avoid ambiguous/parsable names.","triggerScenarios":"POST /api/bookmark/renameBookmark {oldBookmark, newBookmark} (or MCP bookmark tool / CLI bookmark command) with a newBookmark containing a Markdown marker character such as '#inbox', '*important', '>note', or '-todo'.","commonSituations":"User pasting a Markdown-flavored label; tooling that prefixes labels with # (a common 'tag' convention) — which collides with the heading marker.","solutions":["Strip or replace Markdown marker characters from the new bookmark name before submitting.","Validate client-side by replicating treenode.ContainsMarker's character set.","Prefer plain alphanumeric + space/CJK names for bookmarks."],"exampleFix":"// before\nmodel.RenameBookmark(old, '#inbox-2024')\n\n// after: remove leading markers and inline Markdown syntax chars\nname := strings.TrimLeft(newBookmark, \"#*>-=+~` \")\nmodel.RenameBookmark(old, name)","handlingStrategy":"validation","validationCode":"// Strip Markdown marker characters before renaming a bookmark.\nif c := treenode.ContainsMarker(newBookmark); c != \"\" {\n    newBookmark = strings.Map(func(r rune) rune {\n        if treenode.ContainsMarker(string(r)) != \"\" { return -1 }\n        return r\n    }, newBookmark)\n}","typeGuard":null,"tryCatchPattern":"// HTTP caller: surface the offending marker so the user can fix the name.\nif (r.code === -1 && /Markdown syntax marker/i.test(r.msg)) {\n    showFieldError('newBookmark', r.msg) // message includes the [%s] char\n}","preventionTips":["Forbid Markdown marker characters in the bookmark input field client-side.","Avoid the '#tag' convention for bookmark names; use plain labels."],"tags":["bookmark","validation","markdown"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}