siyuan-note/siyuan · error

Conf.Language(151) (localized invalid filename message)

Error message

Conf.Language(151) (localized invalid filename message)

What it means

During RenameAsset, after trimming and filtering the requested new name, it is validated with gulu.File.IsValidFilename. If the resulting name is empty after filtering or contains characters invalid for a filename on supported platforms, the function returns Conf.Language(151), the localized "invalid filename" message, and aborts the rename.

Source

Thrown at kernel/model/assets.go:1665

	// 加密笔记本的资源磁盘文件名参与 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
	}
	if err = ensureReadableAssetLocal(oldAbsPath); err != nil {
		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 {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Provide a new name containing only valid filename characters (letters, digits, CJK, hyphen, underscore).
  2. Avoid path separators and OS-reserved characters like / \ : * ? " < > |.
  3. Ensure the name is non-empty after trimming; a whitespace-only name is rejected.
  4. Strip or replace forbidden characters before calling the API instead of relying on the filter to fail.

Example fix

// before
renameAsset(oldPath, "report/2026: final?")   // rejected
// after
renameAsset(oldPath, "report-2026-final")     // valid filename
Defensive patterns

Strategy: validation

Validate before calling

const FORBIDDEN = /[/\\:*?"<>|\u0000-\u001f]/;
function isValidNewAssetName(name) {
  return typeof name === 'string' && name.trim().length > 0 && !FORBIDDEN.test(name.trim());
}
if (!isValidNewAssetName(newName)) throw new Error('invalid filename');

Type guard

function isSafeFilename(v) {
  return typeof v === 'string' && v.trim().length > 0 && !/[/\\:*?"<>|]/.test(v.trim());
}

Try / catch

try {
  await fetchPost('/api/asset/renameAsset', {oldPath, newName});
} catch (e) {
  if (isInvalidFilenameError(e)) {
    showInputError('Name contains forbidden characters or is empty');
  }
}

Prevention

When it happens

Trigger: Calling the asset-rename API with a newName that is empty, contains forbidden characters (e.g. \/:*?"<>| or control chars), is a reserved name, or reduces to empty after util.FilterUploadFileName strips invalid parts.

Common situations: Users typing names with slashes or OS-reserved characters; copy-pasting titles containing illegal characters; submitting an empty name; names consisting only of characters the filter removes (spaces/dots).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/b2d23ac265b82bb5. Report an issue: GitHub.