siyuan-note/siyuan · error
invalid export path
Error message
invalid export path
What it means
exportedFilePath reverses the '/export/' URL produced by exportedFileURL: it strips the prefix, URL-decodes the remainder, and joins it under the kernel temp export dir. If exportPath does not start with '/export/' or the encoded part is empty, it returns 'invalid export path' — the caller passed a path that never came from the bundle exporter.
Source
Thrown at kernel/model/notebook_bundle.go:188
}
closed = true
finalPath := filepath.Join(util.TempDir, "export", baseFolderName+".sy.zip")
if err = os.Remove(finalPath); nil != err && !os.IsNotExist(err) {
logging.LogErrorf("remove previous notebook bundle failed: %s", err)
return ""
}
if err = os.Rename(partialPath, finalPath); nil != err {
logging.LogErrorf("publish notebook bundle failed: %s", err)
return ""
}
return "/export/" + url.PathEscape(filepath.Base(finalPath))
}
func exportedFilePath(exportPath string) (ret string, err error) {
encoded, ok := strings.CutPrefix(exportPath, "/export/")
if !ok || encoded == "" {
return "", errors.New("invalid export path")
}
decoded, err := url.PathUnescape(encoded)
if nil != err {
return "", err
}
ret = filepath.Join(util.TempDir, "export", filepath.FromSlash(decoded))
if !gulu.File.IsSubPath(filepath.Join(util.TempDir, "export"), ret) {
return "", errors.New("export path is outside export directory")
}
return
}
// ImportSYNotebookBundle 导入批量笔记本包。普通 .sy.zip 返回 bundle=false,由原有导入流程继续处理。
func ImportSYNotebookBundle(zipPath string) (boxIDs []string, bundle bool, err error) {
archive, openErr := zip.OpenReader(zipPath)
if nil != openErr {
err = openErr
returnView on GitHub (pinned to 8641553a1f)
Solutions
- Pass the exact URL string returned by exportedFileURL, unmodified
- Skip entries whose path does not start with '/export/'
- Ensure the encoded segment is non-empty before calling
Example fix
// before
exportedFilePath(entry.path) // entry.path = 'assets/foo.png'
// after
if (strings.HasPrefix(entry.path, "/export/")) {
exportedFilePath(entry.path)
} Defensive patterns
Strategy: validation
Validate before calling
function isExportURL(p){ return typeof p === 'string' && p.startsWith('/export/') && p.length > '/export/'.length; } Type guard
function asExportPath(v){ return typeof v === 'string' && v.startsWith('/export/') && v.length > 8 ? v : null; } Try / catch
ret, err := exportedFilePath(p); if err != nil { if errors.Is(err, errInvalidExportPath) || err.Error() == "invalid export path" { skipEntry(p); return; } return err; } Prevention
- Reuse URLs exactly as produced by the exporter
- Filter entries by the '/export/' prefix before processing
- Don't concatenate your own export paths
When it happens
Trigger: exportNotebooksSYBundle (or tests) calling exportedFilePath with a string lacking the '/export/' prefix, an empty suffix ('/export/'), or a hand-built relative path.
Common situations: Scripts storing/replaying export URLs after modifying them; passing a filesystem path instead of the '/export/...' URL; empty-name entries produced by upstream listing bugs.
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
- result.Msg
- export source [%s] is not a regular file
- invalid path
- asset path must be absolute
- path is not under an assets directory: %s
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/762eb6682e40be26.
Report an issue: GitHub.