siyuan-note/siyuan · error

invalid heading fold scope

Error message

invalid heading fold scope

What it means

GetHeadingFoldTransaction folds a heading according to a scope (children/direct children/siblings). If the scope string is anything other than the recognized values, the switch falls to default and returns 'invalid heading fold scope'. The recognized scopes are the literal cases in the switch, e.g. 'children', 'directChildren', 'siblings'.

Source

Thrown at kernel/model/heading.go:61

	heading := treenode.GetNodeInTree(tree, id)
	transaction = &Transaction{}
	if nil == heading || ast.NodeHeading != heading.Type {
		return
	}

	var headings []*ast.Node
	switch scope {
	case "children":
		if treenode.IsSelfFolded(heading) {
			headings = []*ast.Node{heading}
		} else {
			headings = treenode.HeadingDirectChildren(heading)
		}
	case "siblings":
		headings = treenode.HeadingSiblings(heading)
	default:
		err = errors.New("invalid heading fold scope")
		return
	}
	transaction = buildHeadingFoldTransaction(headings)
	return
}

func buildHeadingFoldTransaction(headings []*ast.Node) (transaction *Transaction) {
	transaction = &Transaction{}
	foldAll := false
	for _, heading := range headings {
		if !treenode.IsSelfFolded(heading) {
			foldAll = true
			break
		}
	}

	for i := len(headings) - 1; 0 <= i; i-- {
		heading := headings[i]

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Use exactly one of the supported scope strings as implemented in the switch ('children', 'directChildren', 'siblings')
  2. Check the transaction payload sent by the client and log the actual scope value
  3. Update the client to a version matching the kernel API

Example fix

// before
const action = {action: 'foldHeading', id: headingID, scope: 'subtree'};
// after
const action = {action: 'foldHeading', id: headingID, scope: 'children'}; // 'children' | 'directChildren' | 'siblings'
Defensive patterns

Strategy: validation

Validate before calling

const SCOPES = new Set(['children', 'directChildren', 'siblings']);
if (!SCOPES.has(scope)) throw new Error('invalid heading fold scope: ' + scope);

Type guard

const isFoldScope = (s) => ['children', 'directChildren', 'siblings'].includes(s);

Try / catch

try {
  await sendTransaction(action);
} catch (e) {
  if (String(e.msg).includes('invalid heading fold scope')) {
    console.error('scope must be children | directChildren | siblings');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling GetHeadingFoldTransaction (HTTP /api/transactions getHeadingFoldTransaction) with a fold action whose scope parameter is misspelled, empty, or in a different casing than the kernel expects.

Common situations: Plugin authors guessing scope names; API clients written against outdated docs; camelCase vs concatenated casing mismatches such as 'direct_children' vs 'directChildren'.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/608a4ef29d00df46. Report an issue: GitHub.