siyuan-note/siyuan · error

invalid asset filename

Error message

invalid asset filename

What it means

After sanitizing the file name (util.FilterUploadFileName) and normalizing the extension to lowercase, InsertAssetBytes requires a non-empty base name and a non-empty extension. If the sanitized name collapses to empty/'.' or the file has no extension, it refuses to build the asset path, because assets are addressed by name+extension and an extension-less name would produce ambiguous/broken asset references.

Solutions

  1. Always pass a file name with a proper extension, e.g. 'diagram.png' instead of 'diagram'
  2. Inspect what FilterUploadFileName strips: pre-clean the name of characters it removes so a non-empty base survives
  3. Default a sensible extension in the caller when the source has none (e.g. derive from MIME type)
  4. Validate the name in the caller: non-empty base, non-empty '.'-prefixed ext before calling

Example fix

// before
model.InsertAssetBytes(id, "image", data)
// after
name := "image"
if filepath.Ext(name) == "" {
    name += ".png" // derive from actual MIME type when possible
}
model.InsertAssetBytes(id, name, data)
Defensive patterns

Strategy: validation

Validate before calling

base := filepath.Base(fileName)
if base == "" || base == "." || filepath.Ext(base) == "" {
    return errors.New("asset file name must include an extension")
}

Type guard

func hasNameAndExt(name string) bool {
    b := filepath.Base(name)
    return b != "" && b != "." && filepath.Ext(b) != ""
}

Try / catch

assetPath, _, err := model.InsertAssetBytes(id, fileName, data)
if err != nil && strings.Contains(err.Error(), "invalid asset filename") {
    fileName = ensureExtension(fileName) // e.g. append from MIME type, retry once
}

Prevention

When it happens

Trigger: Calling InsertAssetBytes with fileName that has no extension ('image', '.hidden' cases where ext resolves empty), a name made entirely of characters stripped by FilterUploadFileName (illegal/path characters), or an empty fileName string.

Common situations: Generating assets with a programmatic name like 'screenshot' and forgetting '.png'; temp-file names or names derived from URLs without decoding to a file name; names containing only reserved characters on the target OS.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/999103b4cef6c30a. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/upload.go:55

	"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 := assetNameWithoutID(filepath.Base(existAssetPath))
		if strings.EqualFold(assetNameWithoutID(fName), originalName) {
			return strings.TrimPrefix(existAssetPath, "/"), false, nil
		}

View on GitHub (pinned to 9f775e8a12)