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

  1. Include both options in the operation data, e.g. {"includeChildren":true,"originalToEmbed":false}
  2. Ensure operation.Data is a JSON object, not a string or block content
  3. 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

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


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)