vitessio/vitess · error

VT13001

VT13001

Error message

err.Error()

What it means

VT13001 is thrown when createDeleteOpWithTarget cannot fetch TableInfo for a DML target table set. Delete-with-input planning resolves each DML target constituent of the statement; if TableInfoFor returns an error (table not found in the semantic table for that TableSet), the planner wraps the underlying message in VT13001 ('table not found in vschema'). It indicates the delete targets a table that semantic analysis could not map.

Source

Thrown at go/vt/vtgate/planbuilder/operators/delete.go:167

	if del.Comments != nil {
		op = newLockAndComment(op, del.Comments, sqlparser.NoLock)
	}
	return op
}

// getFirstVindex returns the first Vindex, if available
func getFirstVindex(vTbl *vindexes.BaseTable) vindexes.Vindex {
	if len(vTbl.ColumnVindexes) > 0 {
		return vTbl.ColumnVindexes[0].Vindex
	}
	return nil
}

func createDeleteOpWithTarget(ctx *plancontext.PlanningContext, target semantics.TableSet, ignore sqlparser.Ignore) dmlOp {
	ti, err := ctx.SemTable.TableInfoFor(target)
	if err != nil {
		panic(vterrors.VT13001(err.Error()))
	}

	vTbl := ti.GetVindexTable()
	if len(vTbl.PrimaryKey) == 0 {
		panic(vterrors.VT09015())
	}
	tblName, err := ti.Name()
	if err != nil {
		panic(err)
	}

	leftComp := make(sqlparser.ValTuple, 0, len(vTbl.PrimaryKey))
	cols := make([]*sqlparser.ColName, 0, len(vTbl.PrimaryKey))
	for _, col := range vTbl.PrimaryKey {
		colName := sqlparser.NewColNameWithQualifier(col.String(), tblName)
		cols = append(cols, colName)
		leftComp = append(leftComp, colName)
		ctx.SemTable.Recursive[colName] = target

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Read the VT13001 message to identify the unresolved table and confirm it exists in the target keyspace's vschema.
  2. Rewrite the multi-table DELETE as separate single-table DELETE statements.
  3. If FK-driven input planning is the trigger, remove the LIMIT clause or restructure so delete-with-input planning isn't required.
  4. Refresh/redeploy the vschema if the table was recently added or renamed.

Example fix

// before
DELETE orders, order_items FROM orders JOIN order_items ON orders.id = order_items.order_id WHERE orders.created_at < '2024-01-01';

// after
DELETE FROM orders WHERE created_at < '2024-01-01';
DELETE FROM order_items WHERE order_id NOT IN (SELECT id FROM orders);
Defensive patterns

Strategy: validation

Validate before calling

// validate all targets of a multi-table DELETE resolve before executing
for _, target := range deleteTargets(sql) {
    if !keyspaceHasTable(defaultKeyspace, target) {
        return fmt.Errorf("VT13001 guard: target %s not found in keyspace %s", target, defaultKeyspace)
    }
}

Type guard

func isVT13001(err error) bool {
    return strings.Contains(err.Error(), "VT13001")
}

Try / catch

if err := execDelete(sql); err != nil {
    if isVT13001(err) {
        log.Warn("delete target not found; checking vschema", slog.Any("error", err))
        return refreshVschemaAndRetry(sql)
    }
    return err
}

Prevention

When it happens

Trigger: Multi-table DELETE (e.g. DELETE t1, t2 FROM ...) or DELETE with LIMIT on FK-related tables triggers delete-with-input planning; for one of the SemTable.DMLTargets constituents, ctx.SemTable.TableInfoFor(target) fails.

Common situations: Multi-table deletes referencing tables not present/authorized in the keyspace vschema; typos in qualified names inside multi-table DELETE syntax; stale vschema after a table rename during a rolling migration.

Related errors


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