vitessio/vitess · error

VT13001

VT13001

Error message

Swap can only be used when the second argument is an input to the first

What it means

VT13001 is an internal error code used for cases that indicate a bug in Vitess' planbuilder. The generic Swap operator rewrite asserts that when swapping a parent and child operator, the child must actually be an input of the parent; if the rewriter failed to locate the child among the parent's inputs, this internal invariant was violated.

Source

Thrown at go/vt/vtgate/planbuilder/operators/rewriters.go:196

		}
	}

	c := child.Inputs()
	if len(c) != 1 {
		panic(vterrors.VT13001("Swap can only be used on single input operators"))
	}

	aInputs := slices.Clone(parent.Inputs())
	var tmp Operator
	for i, in := range aInputs {
		if in == child {
			tmp = aInputs[i]
			aInputs[i] = c[0]
			break
		}
	}
	if tmp == nil {
		panic(vterrors.VT13001("Swap can only be used when the second argument is an input to the first"))
	}

	child.SetInputs([]Operator{parent})
	parent.SetInputs(aInputs)

	return child, Rewrote(message)
}

func bottomUp(
	root Operator,
	rootID semantics.TableSet,
	resolveID func(Operator) semantics.TableSet,
	rewriter VisitF,
	shouldVisit ShouldVisit,
	isRoot bool,
) (Operator, *ApplyResult) {
	if shouldVisit != nil && !shouldVisit(root) {
		return root, NoRewrite

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify the child operator is actually an input of the parent before calling Swap
  2. File a bug with the query and schema if this surfaces from a standard query
  3. Pin/check the Vitess version — this may be a fixed planner bug

Example fix

// before
operator.Swap(ctx, parent, child) // panics if child is not an input of parent
// after
if slices.Contains(parent.Inputs(), child) {
    operator.Swap(ctx, parent, child)
} else {
    return parent, false // skip rewrite
}
Defensive patterns

Strategy: validation

Validate before calling

func canSwap(parent Operator, child Operator) bool {
    return slices.Contains(parent.Inputs(), child)
}
// call Swap only if canSwap(parent, child)

Type guard

func isChildOf(parent, child Operator) bool { return slices.Contains(parent.Inputs(), child) }

Prevention

When it happens

Trigger: Calling the Swap rewriter with a (parent, child) pair where the child is not present in parent's input list — i.e. `parent.Inputs()` does not contain the child being swapped.

Common situations: Custom operator rewriters or new planning rules calling Swap with an operator pair whose relationship was assumed but not verified; usually surfaced during development of new Vitess planning features rather than by end users.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/3142af8f8b11025e. Report an issue: GitHub.