siyuan-note/siyuan · error

ErrBlockNotFound

ErrBlockNotFound

Error message

block not found

What it means

ErrBlockNotFound is the sentinel for a block that cannot be located — either the block ID does not resolve in the tree/index, or (as in publish-serving paths) access control intentionally reports the block as nonexistent to avoid leaking its existence. Callers compare with errors.Is or match its .Error() string.

Solutions

  1. Verify the block ID exists via /api/block/getBlockInfo or a SQL query (blocks table) before use
  2. If this is a publish instance, enable publish access for the block/doc or access it from the authenticated kernel instead
  3. Clean up stale references (attribute view bindings, links) pointing to deleted blocks
  4. Return/handle the sentinel explicitly so clients get a stable 'block not found' signal rather than a generic error

Example fix

// before
ret.Msg = "block missing"

// after
if !model.CheckBlockIdMetadataAccessableByPublishAccessInBox(c, publishAccess, id, notebook) {
    ret.Code = -1
    ret.Msg = model.ErrBlockNotFound.Error()
    return contractFailure[string](ret)
}
Defensive patterns

Strategy: validation

Validate before calling

// TypeScript: confirm the block exists before dependent calls
const info = await fetchPost('/api/block/getBlockInfo', { id });
if (info.code !== 0) throw new Error('block missing: ' + id);

Type guard

function isBlockNotFound(msg: string | null | undefined): boolean {
  return msg === 'block not found';
}

Try / catch

// Go
if errors.Is(err, model.ErrBlockNotFound) {
    // treat as missing (or hidden on publish instances) rather than a crash
    return apicontract.Success(model.ErrBlockNotFound.Error())
}

Prevention

When it happens

Trigger: Publish/publish-access checks (kernel/api/block.go:488, kernel/api/filetree.go:333) return ErrBlockNotFound.Error() when isBlockPublishAccessible / CheckBlockIdMetadataAccessableByPublishAccessInBox denies access; also returned by binding validators (preflightAttributeViewCellBindings, validateAttributeViewBinding) and contract getters when the block ID is absent.

Common situations: Requesting a block ID that was deleted or whose doc was removed; accessing unpublished blocks through the publish server; stale IDs saved in attribute views or plugins after docs were restructured; ID case/whitespace mistakes.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/dc43f913058ecb0a. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/tree.go:212

			return
		}
	}

	if err = treenode.CheckSpecJSON(data); nil != err {
		return
	}
	ret, err = dataparser.ParseJSONWithoutFix(data, luteEngine.ParseOptions)
	if err != nil {
		logging.LogErrorf("parse json to tree [%s] failed: %s", localPath, err)
		return
	}
	return
}

var (
	ErrBoxNotFound   = errors.New("notebook not found")
	ErrBoxClosed     = errors.New("notebook closed")
	ErrBlockNotFound = errors.New("block not found")
	ErrTreeNotFound  = errors.New("tree not found")
	ErrIndexing      = errors.New("indexing")
	ErrBoxUnindexed  = errors.New("notebook unindexed")
	ErrInvalidID     = errors.New("invalid id")
)

func LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) {
	return LoadTreeByBlockIDWithReindexInBox(id, "")
}

// LoadTreeByBlockIDWithReindexInBox 与 LoadTreeByBlockIDWithReindex 一致,但按 boxID 路由 blocktree 查询。
func LoadTreeByBlockIDWithReindexInBox(id, boxID string) (ret *parse.Tree, err error) {
	if "" == id {
		logging.LogWarnf("block id is empty")
		return nil, ErrTreeNotFound
	}

	bt := treenode.GetBlockTreeInBox(id, boxID)

View on GitHub (pinned to 9f775e8a12)