siyuan-note/siyuan · warning
Do not include symbols \ / : * ? " ' < > |
Error message
Do not include symbols \ / : * ? " ' < > |
What it means
Returned by RenameAsset (assets.go:1511) when the new asset name fails gulu.File.IsValidFilename after trimming and util.FilterUploadFileName. The message is the kernel i18n key 151 listing forbidden characters: backslash, slash, colon, asterisk, question mark, double-quote, single-quote, less-than, greater-than, pipe. The HTML-entity form (" ' < >) is used because the string is rendered in the UI.
Source
Thrown at kernel/model/assets.go:1511
// 加密笔记本的资源磁盘文件名参与 AAD,重命名需要重新封装密文,当前不支持。
if absPath, absErr := GetAssetAbsPathInBox(oldPath, ""); absErr == nil {
if IsEncryptedAssetPath(absPath) {
err = errors.New("renaming assets in encrypted notebooks is not supported")
return
}
}
newName = strings.TrimSpace(newName)
newName = util.FilterUploadFileName(newName)
if path.Base(oldCleanPath) == newName {
return
}
if "" == newName {
return
}
if !gulu.File.IsValidFilename(newName) {
err = errors.New(Conf.Language(151))
return
}
newName = util.AssetName(newName+filepath.Ext(oldCleanPath), ast.NewNodeID())
parentDir := path.Dir(oldCleanPath)
newPath = path.Join(parentDir, newName)
oldAbsPath, getErr := GetAssetAbsPathInBox(oldPath, "")
if getErr != nil {
logging.LogErrorf("get asset [%s] abs path failed: %s", oldPath, getErr)
return
}
newAbsPath := filepath.Join(filepath.Dir(oldAbsPath), newName)
filelock.Lock(oldAbsPath)
if err = os.Rename(oldAbsPath, newAbsPath); err != nil {
if err = gulu.File.Copy(oldAbsPath, newAbsPath); err != nil {
filelock.Unlock(oldAbsPath)
logging.LogErrorf("copy asset [%s] failed: %s", oldAbsPath, err)
returnView on GitHub (pinned to 251596fc0d)
Solutions
- Strip or replace the forbidden characters (\ / : * ? < > | and both quote kinds) before calling RenameAsset.
- Run the candidate through gulu.File.IsValidFilename (or an equivalent regex) on the client side so the user gets immediate feedback.
- If the name is user-typed, reject the characters in the input field rather than after submission.
Example fix
// before: passing raw user input
model.RenameAsset(oldPath, userInput)
// after: validate client-side first
const forbidden = /[\\\/:*?"'<>|]/
if (forbidden.test(userInput)) {
showMessage(window.siyuan.languages[151])
return
}
model.RenameAsset(oldPath, userInput) Defensive patterns
Strategy: validation
Validate before calling
// Reject forbidden filename characters before calling renameAsset.
const FORBIDDEN = /[\\\/:*?"'<>|]/
if (!newName || FORBIDDEN.test(newName)) {
showMessage(window.siyuan.languages[151])
return
} Try / catch
// Validate client-side; the kernel will also reject, so surface the i18n tip.
try { await renameAsset(oldPath, newName) }
catch (e) { if (/symbols/i.test(e.message)) highlightBadChars(newName); else throw e } Prevention
- Run a forbidden-character regex on the input field and block submission.
- Sanitize pasted names (strip colons from dates, slashes from paths).
- Remember quotes are also forbidden, not just the Windows reserved set.
When it happens
Trigger: Calling /api/asset/renameAsset with a newName that contains any of \ / : * ? < > | or a quote, is empty after filtering, or otherwise violates the portable-filename rules enforced by gulu.File.IsValidFilename. The check runs after FilterUploadFileName strips some characters, so the residual name still carried a forbidden symbol.
Common situations: User pastes a name with trailing punctuation or a date containing colons (e.g. "img:2024.png"); name copied from a URL with slashes/queries; plugin submits a raw filename without sanitization; cross-platform name using Windows-illegal characters on a Linux host (the guard is OS-independent).
Related errors
- invalid custom emoji name
- assetPath is required for analyze
- only local assets/... images are supported
- assetPath is not an image referenced by the document
- asset path is required
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/79a11266783fb174.
Report an issue: GitHub.