siyuan-note/siyuan · error

current document ID is invalid

Error message

current document ID is invalid

What it means

Returned by ResolveDocVersionBoxID (history_diff.go:122) when ref.Type == "current" but ref.ID fails ast.IsNodeIDPattern. SiYuan block/document IDs are fixed-format 20-character base36-ish tokens; any other shape cannot be looked up in the block tree. The guard prevents a pointless treenode.GetBlockTree lookup and catches malformed input early.

Source

Thrown at kernel/model/history_diff.go:122

	start      int
	end        int
	storedRuns []string
	signature  string
}

type docDiffLCSBudget struct {
	remaining int
}

// ResolveDocVersionBoxID 返回文档版本引用中明确记录的加密笔记本 ID。
func ResolveDocVersionBoxID(ref *DocVersionRef) (string, error) {
	if ref == nil {
		return "", errors.New("document version is required")
	}
	switch ref.Type {
	case docVersionCurrent:
		if !ast.IsNodeIDPattern(ref.ID) {
			return "", errors.New("current document ID is invalid")
		}
		blockTree := treenode.GetBlockTree(ref.ID)
		if blockTree == nil {
			return "", ErrTreeNotFound
		}
		if IsEncryptedBox(blockTree.BoxID) {
			return blockTree.BoxID, nil
		}
		return "", nil
	case docVersionHistory:
		absPath, err := validateHistoryPath(ref.Path)
		if err != nil {
			return "", err
		}
		boxID := ExtractBoxIDFromHistoryPath(absPath)
		if IsEncryptedBox(boxID) {
			return boxID, nil
		}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Validate the ID with ast.IsNodeIDPattern(ref.ID) at the API boundary and return a 400-style message before calling ResolveDocVersionBoxID.
  2. Confirm the ID is the document root ID (20 chars) and not a heading/paragraph child block ID or a timestamp.
  3. If the ID comes from a URL/clipboard, trim whitespace and verify len==20 and all chars are in the node-ID alphabet.

Example fix

// before
ref := &DocVersionRef{Type: "current", ID: userInput}

// after
if ref.Type == "current" && !ast.IsNodeIDPattern(ref.ID) {
    return fmt.Errorf("current document ID is invalid")
}
ref := &DocVersionRef{Type: "current", ID: userInput}
Defensive patterns

Strategy: validation

Validate before calling

if ref == nil || ref.Type != docVersionCurrent {
    return // nothing to validate here
}
if !ast.IsNodeIDPattern(ref.ID) {
    return fmt.Errorf("current document ID is invalid")
}
// safe to call ResolveDocVersionBoxID(ref)

Type guard

// isValidCurrentDocRef reports whether ref is a current-type ref with a valid 20-char block ID.
func isValidCurrentDocRef(ref *DocVersionRef) bool {
    return ref != nil && ref.Type == docVersionCurrent && ast.IsNodeIDPattern(ref.ID)
}

Prevention

When it happens

Trigger: POST /api/history/diffDocVersions with {"type":"current","id":"<garbage>"} or an empty id; a plugin passing a rootID truncated or with whitespace; copy-paste of a 14-char timestamp ID instead of the 20-char block ID.

Common situations: UI passes a doc ID from a stale clipboard; a script concatenates IDs incorrectly; version mismatch where older 14-char IDs are fed to newer kernels.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/0d8cb4f281843567. Report an issue: GitHub.