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

  1. Open the notebook (Conf.OpenBox / the UI) before pinning its documents.
  2. Rebuild the index so stale block-tree entries are removed, then retry with an existing document.
  3. Verify the .sy file exists under data/<boxID>/<path> and restore it if it was deleted.
  4. 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

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


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)