siyuan-note/siyuan · error
The shorthand save notebook is unavailable. Select an…
Error message
The shorthand save notebook is unavailable. Select an opened non-encrypted notebook in Settings - Document
What it means
MoveLocalShorthands requires a valid target notebook for shorthand documents. If IsShorthandSaveBoxAvailable(boxID) reports false — the box is nil, not opened, or encrypted — the function returns i18n message 375 instructing the user to select an opened non-encrypted notebook in the document settings.
Solutions
- Open the target notebook or select another one in Settings - Document as the shorthand save notebook
- Choose a non-encrypted notebook, since encrypted notebooks are rejected as shorthand targets
- Update the shorthand save box configuration to a valid, opened notebook ID before moving
Example fix
// before
model.MoveLocalShorthands(closedOrEncryptedBoxID)
// after
if model.IsShorthandSaveBoxAvailable(boxID) {
model.MoveLocalShorthands(boxID)
} Defensive patterns
Strategy: validation
Validate before calling
const boxes = await api.getNotebooks()
const box = boxes.find(b => b.id === boxID && !b.closed)
if (!box) throw new Error('shorthand save box unavailable; select an opened non-encrypted notebook') Type guard
function isOpenBox(b) { return b != null && !!b.id && b.closed === false } Try / catch
try { await api.moveLocalShorthands(boxID) } catch (e) { if (String(e).includes('shorthand save notebook')) { openSettingsDocument(); } else throw e } Prevention
- Keep the shorthand save notebook open and unencrypted in Settings - Document
- Re-validate the configured box ID on workspace changes or restores
- Handle encrypted notebooks explicitly: pick a different target for shorthands
When it happens
Trigger: Calling MoveLocalShorthands with a boxID that is not currently open, does not exist, or points to an encrypted notebook while the shorthand save notebook setting is unavailable.
Common situations: The configured shorthand save notebook was closed, deleted, or switched to encrypted; config points at a notebook ID from another workspace; fresh install where the shorthand save notebook was never chosen.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/90a06235e525fe9b.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/shortcuts.go:58
func MoveLocalShorthands(boxID string) (retIDs []string, err error) {
shorthandsDir := filepath.Join(util.ShortcutsPath, "shorthands")
if !gulu.File.IsDir(shorthandsDir) {
return
}
if !syncLock.TryLock() {
err = errors.New(Conf.Language(222))
return
}
defer syncLock.Unlock()
entries, err := os.ReadDir(shorthandsDir)
if nil != err {
logging.LogErrorf("read dir [%s] failed: %s", shorthandsDir, err)
return
}
if !IsShorthandSaveBoxAvailable(boxID) {
err = errors.New(Conf.Language(375))
return
}
assetsDir := filepath.Join(util.DataDir, "assets")
for _, entry := range entries {
if entry.IsDir() && "assets" == entry.Name() {
assetsEntries, readErr := os.ReadDir(filepath.Join(shorthandsDir, entry.Name()))
if nil != readErr {
logging.LogErrorf("read dir [%s] failed: %s", shorthandsDir, readErr)
continue
}
for _, assetEntry := range assetsEntries {
if assetEntry.IsDir() {
continue
}
p := filepath.Join(shorthandsDir, entry.Name(), assetEntry.Name())
assetWritePath := filepath.Join(assetsDir, assetEntry.Name())View on GitHub (pinned to 9f775e8a12)