vitessio/vitess · error

executor is closed

Error message

executor is closed

What it means

TabletExecutor.Validate checks a list of SQL statements by parsing DDLs, but refuses to operate once the executor has been closed. isClosed is set after Close(), so any subsequent Validate call returns this error.

Source

Thrown at go/vt/schemamanager/tablet_executor.go:142

		}
		tabletInfo, err := exec.ts.GetTablet(ctx, shardInfo.PrimaryAlias)
		if err != nil {
			return fmt.Errorf("unable to get primary tablet info, keyspace: %s, shard: %s, error: %v", keyspace, shardName, err)
		}
		exec.tablets = append(exec.tablets, tabletInfo.Tablet)
	}

	if len(exec.tablets) == 0 {
		return fmt.Errorf("keyspace: %s does not contain any primary tablets", keyspace)
	}
	exec.isClosed = false
	return nil
}

// Validate validates a list of sql statements.
func (exec *TabletExecutor) Validate(ctx context.Context, sqls []string) error {
	if exec.isClosed {
		return errors.New("executor is closed")
	}
	if err := exec.parseDDLs(sqls); err != nil {
		return err
	}

	return nil
}

func (exec *TabletExecutor) parseDDLs(sqls []string) error {
	for _, sql := range sqls {
		stmt, err := exec.parser.Parse(sql)
		if err != nil {
			return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "failed to parse sql: %s, got error: %v", sql, err)
		}
		switch stmt.(type) {
		case sqlparser.DDLStatement:
		case sqlparser.DBDDLStatement:
		case *sqlparser.RevertMigration:

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Create a new TabletExecutor instance for validation after the previous one was closed
  2. Reorder lifecycle code so Validate happens before Close
  3. Check executor.isClosed (or track closure) before reusing the executor

Example fix

// before
exec.Close()
err := exec.Validate(ctx, sqls) // executor is closed
// after
err := exec.Validate(ctx, sqls)
exec.Close()
Defensive patterns

Strategy: try-catch

Validate before calling

if exec.IsClosed() { exec = schemamanager.NewTabletExecutor(...) }

Try / catch

if err != nil {
	if err.Error() == "executor is closed" {
		// recreate executor and retry once
	}
}

Prevention

When it happens

Trigger: Calling Validate (or executing) on a TabletExecutor after Close() was called on it.

Common situations: Reusing an executor across schema-manager runs or retry logic without creating a new instance; lifecycle bugs where a deferred Close() runs before a later Validate.

Related errors


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