siyuan-note/siyuan · error
document [ ] is unavailable
Error message
document [%s] is unavailable
What it means
After resolving the block-tree record, UpdatePinnedDocs looks up the owning notebook via Conf.Box(bt.BoxID) and stats the .sy file at bt.Path. If the notebook is closed (Conf.Box returns nil) or the document file is missing on disk (Stat returns nil), the document cannot be pinned and this error is returned.
Solutions
- Open the notebook (Conf.OpenBox / the UI) before pinning its documents.
- Rebuild the index so stale block-tree entries are removed, then retry with an existing document.
- Verify the .sy file exists under data/<boxID>/<path> and restore it if it was deleted.
- Pick a document from an opened notebook.
Example fix
// before
model.UpdatePinnedDocs([]string{docID}, "pin", "", false)
// after
if box := model.Conf.Box(bt.BoxID); box == nil || box.Closed {
return errors.New("open the notebook before pinning its documents")
}
model.UpdatePinnedDocs([]string{docID}, "pin", "", false) Defensive patterns
Strategy: validation
Validate before calling
box := model.Conf.Box(bt.BoxID)
if box == nil {
return errors.New("notebook is closed")
}
if box.Stat(bt.Path) == nil {
return errors.New("document file missing on disk")
} Type guard
func docOnDisk(bt *treenode.BlockTree) bool {
box := model.Conf.Box(bt.BoxID)
return box != nil && box.Stat(bt.Path) != nil
} Try / catch
if err := model.UpdatePinnedDocs(ids, "pin", "", false); err != nil {
if strings.Contains(err.Error(), "is unavailable") {
// open the notebook or refresh the index, then retry
}
} Prevention
- Open target notebooks before batch pin operations
- Rebuild the index after external file changes or sync
- Verify .sy files exist before referencing document IDs
- Handle workspace switches that close all notebooks
When it happens
Trigger: Pinning a document whose notebook is closed in the current workspace, or whose .sy file no longer exists (deleted externally, path changed, or block-tree entry stale after sync/move).
Common situations: Notebook closed by the user or by another window; document removed by an external sync client while the block-tree index still references it; workspace switched so the notebook is not opened.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- attribute view not found
- Conf.Language(12) (localized asset-not-found message)
- Conf.Language(315)
- Conf.Language(396)
- content template [ ] not found
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/dd293178b23ef630.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/pinned_docs.go:193
return fmt.Errorf("invalid document ID [%s]", id)
}
if selected[id] {
continue
}
selected[id] = true
if action == "unpin" {
continue
}
bt := treenode.GetBlockTree(id)
if bt != nil && IsEncryptedBox(bt.BoxID) {
return fmt.Errorf("%s", Conf.Language(396))
}
if !isPinnableDocument(bt) {
return fmt.Errorf("document [%s] cannot be pinned", id)
}
box := Conf.Box(bt.BoxID)
if box == nil || box.Stat(bt.Path) == nil {
return fmt.Errorf("document [%s] is unavailable", id)
}
ial := box.docIAL(bt.Path)
if ial == nil {
return fmt.Errorf("cannot read pinned document [%s]", id)
}
if id != bt.BoxID && ial[DocHiddenAttr] == "true" {
return fmt.Errorf("document [%s] cannot be pinned", id)
}
refs = append(refs, pinnedDocRef{ID: id, Notebook: bt.BoxID})
}
if action == "pin" && selected[targetID] {
return nil
}
remaining := []pinnedDocRef{}
for _, ref := range stored.Docs {
if !selected[ref.ID] {
remaining = append(remaining, ref)
}View on GitHub (pinned to 9f775e8a12)