siyuan-note/siyuan · error

invalid asset filename

Error message

invalid asset filename

What it means

Thrown by InsertAssetBytes when the filename, after sanitization by util.FilterUploadFileName and extension normalization, is empty, is just a dot, or has no extension. The function requires a valid base name with an extension to compute the on-disk asset filename via util.AssetName or encryptedAssetName.

Source

Thrown at kernel/model/upload.go:54

	"github.com/siyuan-note/siyuan/kernel/util"
)

// InsertAssetBytes 将内存中的资源直接写入目标文档资源目录,避免生成内容经过明文临时文件。
func InsertAssetBytes(id, fileName string, data []byte) (assetPath string, created bool, err error) {
	bt := treenode.GetBlockTree(id)
	if bt == nil {
		return "", false, errors.New(Conf.Language(71))
	}
	if len(data) == 0 {
		return "", false, errors.New("asset data is empty")
	}

	baseName := filepath.Base(fileName)
	fName := util.FilterUploadFileName(baseName)
	ext := strings.ToLower(filepath.Ext(fName))
	fName = strings.TrimSuffix(fName, filepath.Ext(fName)) + ext
	if fName == "" || fName == "." || ext == "" {
		return "", false, errors.New("invalid asset filename")
	}

	docDirLocalPath := filepath.Join(util.DataDir, bt.BoxID, path.Dir(bt.Path))
	assetsDirPath := getAssetsDir(filepath.Join(util.DataDir, bt.BoxID), docDirLocalPath)
	if err = os.MkdirAll(assetsDirPath, 0755); err != nil {
		return "", false, err
	}

	reader := bytes.NewReader(data)
	hash, err := util.GetEtagByHandle(reader, int64(len(data)))
	if err != nil {
		return "", false, err
	}
	if existAssetPath := GetAssetPathByHash(hash, bt.BoxID); existAssetPath != "" {
		originalName := util.RemoveID(filepath.Base(existAssetPath))
		if strings.EqualFold(fName, originalName) {
			return strings.TrimPrefix(existAssetPath, "/"), false, nil
		}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Ensure the fileName parameter includes a proper extension (e.g., 'image.png')
  2. If the source filename is unreliable, derive the extension from the MIME type before calling InsertAssetBytes
  3. Sanitize the filename client-side and reject filenames without extensions before sending

Example fix

// before
assetPath, _, err := model.InsertAssetBytes(id, "screenshot", data)

// after
ext := mimeToExt(mimeType) // e.g. "png"
assetPath, _, err := model.InsertAssetBytes(id, "screenshot."+ext, data)
Defensive patterns

Strategy: validation

Validate before calling

ext := filepath.Ext(fileName)
if ext == "" {
    ext = mimeToExt(contentType) // derive from MIME type
    fileName = fileName + "." + ext
}
if fileName == "" || ext == "" {
    return errors.New("asset filename must have a valid extension")
}
assetPath, _, err := model.InsertAssetBytes(id, fileName, data)

Prevention

When it happens

Trigger: Passing a fileName that is empty, consists only of invalid characters stripped by FilterUploadFileName, has no file extension, or normalizes to '.' after processing. Example: fileName = "..." or fileName = "file" (no extension).

Common situations: Client-side code constructs a filename programmatically and forgets the extension; a download pipeline strips the extension; the original filename contained only characters that FilterUploadFileName removes.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/999103b4cef6c30a. Report an issue: GitHub.