siyuan-note/siyuan · error
invalid .sy base name [%s]: must end with .sy
Error message
invalid .sy base name [%s]: must end with .sy
What it means
Returned by `filesys.SyObjectBase` when the basename of a `.sy` path does not end with the `.sy` suffix. `SyObjectBase` extracts the stable file basename used to bind encryption AAD (`siyuan:file:<boxID>:<base>`), so the extension is part of the cryptographic identity; an unrecognized extension is rejected rather than silently producing undecryptable data.
Source
Thrown at kernel/filesys/crypto_hook.go:112
}()
aad, err := SyAAD(boxID, relativePath)
if err != nil {
return nil, err
}
return util.DecryptWithAAD(fileKey, data, []byte(aad))
}
// SyObjectBase 从 box 内相对路径提取稳定文件基名并校验合法性。
// 接受形如 <rootID>.sy 的基名:扩展名必须是 .sy,且 stem 是合法节点 ID。
// 非法扩展名或非节点 ID 模式返回错误,避免把任意路径当 AAD 绑定物产生不可解密的数据。
// 由 filesys、model 历史查看/回滚、import 等所有 .sy 加解密路径共同使用,保证 AAD 一致。
func SyObjectBase(relativePath string) (string, error) {
base := relativePath
if idx := strings.LastIndexAny(relativePath, "/\\"); idx >= 0 {
base = relativePath[idx+1:]
}
if !strings.HasSuffix(base, ".sy") {
return "", fmt.Errorf("invalid .sy base name [%s]: must end with .sy", base)
}
stem := strings.TrimSuffix(base, ".sy")
if !ast.IsNodeIDPattern(stem) {
return "", fmt.Errorf("invalid .sy base name [%s]: stem is not a node ID", base)
}
return base, nil
}
// SyAAD 构造 .sy 密文的 AAD:siyuan:file:<boxID>:<稳定文件基名>。
// 父目录不进 AAD——同 box 内文件名不变的移动允许原样 Rename 密文,内容/box/类型/对象 ID 仍受认证。
func SyAAD(boxID, relativePath string) (string, error) {
base, err := SyObjectBase(relativePath)
if err != nil {
return "", err
}
return "siyuan:file:" + boxID + ":" + base, nil
}
View on GitHub (pinned to 251596fc0d)
Solutions
- Ensure the path argument points at a `<rootID>.sy` file before calling `SyObjectBase`/`SyAAD`.
- Route non-`.sy` files through the correct helper (asset/AV encryption uses different AAD construction).
- If the path is user-supplied, validate `strings.HasSuffix(base, ".sy")` upstream.
Example fix
// before
base, err := filesys.SyObjectBase("20240101000000-abc1234.json")
// after
base, err := filesys.SyObjectBase("20240101000000-abc1234.sy") Defensive patterns
Strategy: type-guard
Validate before calling
// Confirm .sy suffix before calling SyObjectBase/SyAAD:
base := p
if idx := strings.LastIndexAny(p, "/\\"); idx >= 0 {
base = p[idx+1:]
}
if !strings.HasSuffix(base, ".sy") {
return "", fmt.Errorf("not a .sy file: %s", base)
} Type guard
func isSyPath(p string) bool {
base := p
if idx := strings.LastIndexAny(p, "/\\"); idx >= 0 {
base = p[idx+1:]
}
return strings.HasSuffix(base, ".sy")
} Prevention
- Route only .sy files through SyObjectBase; use the asset/AV AAD helpers for those types.
- Centralize encryption-AAD construction so callers cannot pass the wrong path type.
- Unit-test the helper with .json/.md/.sy inputs to lock the contract.
When it happens
Trigger: Calling `SyObjectBase` or `SyAAD` with a path whose last segment is not a `.sy` file (e.g. `foo.json`, `bar.md`, a directory, or a path with no extension). This commonly happens when a non-`.sy` relative path is routed through the encrypted-file hook.
Common situations: Passing an asset or attribute-view JSON path to the `.sy` AAD helper; mismatched extension after a rename/import; calling the encryption hook for a temporary file.
Related errors
- invalid .sy base name [%s]: stem is not a node ID
- refuse to write decrypted asset inside workspace
- source is not an encrypted asset
- import path is not sub path of import dir
- path belongs to encrypted notebook [%s]: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/068182d284d9d70f.
Report an issue: GitHub.