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
- Use exactly one of the supported scope strings as implemented in the switch ('children', 'directChildren', 'siblings')
- Check the transaction payload sent by the client and log the actual scope value
- 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
- Keep the scope strings in a shared constant instead of inlining literals
- Match the casing used by the kernel exactly
- Test fold transactions with each supported scope once
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
- invalid new item template target type [%s]
- invalid appearance mode: %s
- invalid asset download mode
- invalid card aspect ratio preset [%v]
- invalid card size preset [%v]
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/608a4ef29d00df46.
Report an issue: GitHub.