siyuan-note/siyuan · error · TxErr
invalid block swap options
Error message
invalid block swap options
What it means
The swap operation's Data payload failed to unmarshal into blockSwapOptions, or one of the required boolean options IncludeChildren or OriginalToEmbed was nil. Both option pointers must be present and non-null so the kernel knows whether child blocks and embed blocks participate in the swap.
Solutions
- Include both options in the operation data, e.g. {"includeChildren":true,"originalToEmbed":false}
- Ensure operation.Data is a JSON object, not a string or block content
- Verify field names match the current blockSwapOptions schema (camelCase)
Example fix
// before
{"action":"swap-block-ref","id":"<refId>","blockID":"<defId>","data":{"includeChildren":true}}
// after
{"action":"swap-block-ref","id":"<refId>","blockID":"<defId>","data":{"includeChildren":true,"originalToEmbed":false}} Defensive patterns
Strategy: validation
Validate before calling
const d = op.data;
if (typeof d !== 'object' || d === null || typeof d.includeChildren !== 'boolean' || typeof d.originalToEmbed !== 'boolean') {
throw new Error('swap-block-ref data requires includeChildren and originalToEmbed booleans');
} Type guard
function isValidSwapOptions(d) {
return typeof d === 'object' && d !== null && typeof (d).includeChildren === 'boolean' && typeof (d).originalToEmbed === 'boolean';
} Prevention
- Always set both includeChildren and originalToEmbed explicitly
- Keep swap options construction in one shared helper validated against the schema
- Check field names are camelCase per blockSwapOptions
When it happens
Trigger: Calling the transactions API with a swap-block-ref operation whose data JSON omits 'includeChildren' or 'originalToEmbed', or whose data is not valid JSON / not an options object.
Common situations: Hand-written API calls or scripts constructing swap operations; plugin code updated to a newer options schema that renamed fields; sending the raw block content instead of an options object in data.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- block swap requires two non-document blocks
- element [ ]
- empty JSON value
- entry [ ]
- Field [conf] should be of type [Object]
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/8cba03847b91f2be.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/transaction_block_swap.go:53
if len(tx.DoOperations) != 1 {
return fail(errors.New("block swap must be submitted as a separate transaction"))
}
if tx.isReplay {
if operation.blockSwapState == nil {
return fail(errors.New("block swap undo state is unavailable"))
}
if err := tx.replayBlockSwap(operation); err != nil {
return fail(err)
}
return nil
}
data, err := json.Marshal(operation.Data)
if err != nil {
return fail(err)
}
var options blockSwapOptions
if err = json.Unmarshal(data, &options); err != nil || options.IncludeChildren == nil || options.OriginalToEmbed == nil {
return fail(errors.New("invalid block swap options"))
}
refTree, err := tx.loadTree(operation.ID)
if err != nil {
return fail(err)
}
defTree, err := tx.loadTree(operation.BlockID)
if err != nil {
return fail(err)
}
if !IsSameCryptoBoundary(refTree.Box, defTree.Box) {
return fail(errors.New("cannot swap blocks across encrypted notebook boundaries"))
}
ref := treenode.GetNodeInTree(refTree, operation.ID)
def := treenode.GetNodeInTree(defTree, operation.BlockID)
if err = validateBlockSwap(ref, def, *options.IncludeChildren); err != nil {
return fail(err)
}
trees := []*parse.Tree{refTree}View on GitHub (pinned to 9f775e8a12)