vitessio/vitess · error

direct DDL is disabled

Error message

direct DDL is disabled

What it means

ErrDirectDDLDisabled is a sentinel error returned by TryExecute when a direct (in-place) DDL statement is attempted while direct DDL is disabled in the tablet's online-DDL configuration. It forces users to route schema changes through online DDL (gh-ost/pt-osc) or explicitly re-enable direct DDL.

Source

Thrown at go/vt/schema/online_ddl.go:51

var (
	onlineDdlUUIDRegexp               = regexp.MustCompile(`^[0-f]{8}_[0-f]{4}_[0-f]{4}_[0-f]{4}_[0-f]{12}$`)
	onlineDDLGeneratedTableNameRegexp = regexp.MustCompile(`^_[0-f]{8}_[0-f]{4}_[0-f]{4}_[0-f]{4}_[0-f]{12}_([0-9]{14})_(gho|ghc|del|new|vrepl)$`)
	ptOSCGeneratedTableNameRegexp     = regexp.MustCompile(`^_.*_old$`)
	migrationContextValidatorRegexp   = regexp.MustCompile(`^[\w:-]*$`)
)

var onlineDDLInternalTableHintsMap = map[string]bool{
	"vrp": true, // vreplication
	"gho": true, // gh-ost
	"ghc": true, // gh-ost
	"del": true, // gh-ost
	"new": true, // pt-osc
}

var (
	// ErrDirectDDLDisabled is returned when direct DDL is disabled, and a user attempts to run a DDL statement
	ErrDirectDDLDisabled = errors.New("direct DDL is disabled")
	// ErrOnlineDDLDisabled is returned when online DDL is disabled, and a user attempts to run an online DDL operation (submit, review, control)
	ErrOnlineDDLDisabled = errors.New("online DDL is disabled")
	// ErrForeignKeyFound indicates any finding of FOREIGN KEY clause in a DDL statement
	ErrForeignKeyFound = errors.New("Foreign key found")
	// ErrRenameTableFound indicates finding of ALTER TABLE...RENAME in ddl statement
	ErrRenameTableFound = errors.New("RENAME clause found")
)

const (
	SchemaMigrationsTableName = "schema_migrations"
	RevertActionStr           = "revert"
)

// ValidateMigrationContext validates that the given migration context only uses valid characters
func ValidateMigrationContext(migrationContext string) error {
	if migrationContextValidatorRegexp.MatchString(migrationContext) {
		return nil
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Use an online DDL strategy: prefix the statement with a comment like /*vt+ ddl_strategy=gh-ost */ or set -ddl_strategy appropriately
  2. Change the tablet's ddl_strategy flag to allow direct DDL (e.g. 'direct') if acceptable for the operation
  3. Route the change through vtctldclient ApplySchema for coordinated application
  4. Check errors.Is(err, schema.ErrDirectDDLDisabled) in tooling to present a friendly message

Example fix

-- before
ALTER TABLE t ADD COLUMN c INT;
-- after
ALTER /*vt+ ddl_strategy=gh-ost */ TABLE t ADD COLUMN c INT;
Defensive patterns

Strategy: validation

Validate before calling

strategy := viper.GetString("ddl_strategy")
if !strings.Contains(strategy, "direct") && isDirectDDL(stmt) {
    return fmt.Errorf("rewrite %s with ddl_strategy=online or enable direct DDL", stmt)
}

Try / catch

_, err := tm.TryExecute(ctx, stmt)
if errors.Is(err, schema.ErrDirectDDLDisabled) {
    // fall back to online DDL strategy or surface config guidance
}

Prevention

When it happens

Trigger: Submitting a plain DDL statement (ALTER/CREATE/DROP without an online-DDL prefix) to the vttablet ExecuteApiPath / query service with -ddl_strategy set such that direct DDL is disallowed (e.g. ddl_strategy='online' or empty direct allowance).

Common situations: Environments where operators disabled direct DDL to protect production (long ALTERs locking tables); CI clusters configured for online-DDL only; users unaware that ddl_strategy governs direct vs online execution.

Related errors


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