{"record":{"id":"837c813bc1bd6d6d","repo":"vitessio/vitess","slug":"batch-size-requires-direct-ddl-strategy","errorCode":null,"errorMessage":"--batch-size requires 'direct' ddl_strategy","messagePattern":"--batch-size requires 'direct' ddl_strategy","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/schemamanager/tablet_executor.go","lineNumber":467,"sourceCode":"\t\t\t\t\treloadCtx,\n\t\t\t\t\texec.ts,\n\t\t\t\t\texec.tmc,\n\t\t\t\t\texec.logger,\n\t\t\t\t\texec.keyspace,\n\t\t\t\t\tresult.Shard,\n\t\t\t\t\tresult.Position,\n\t\t\t\t\tconcurrency,\n\t\t\t\t\ttrue, /* includePrimary */\n\t\t\t\t)\n\t\t\t}(result)\n\t\t}\n\t\twg.Wait()\n\t}()\n\n\tif exec.batchSize > 1 {\n\t\t// Before we proceed to batch, we need to validate there's no conflicts.\n\t\tif !exec.isDirectStrategy() {\n\t\t\treturn errorExecResult(errors.New(\"--batch-size requires 'direct' ddl_strategy\"))\n\t\t}\n\t\tif exec.hasProvidedUUIDs() {\n\t\t\treturn errorExecResult(errors.New(\"--batch-size conflicts with --uuid-list. Batching does not support UUIDs.\"))\n\t\t}\n\t\tallSQLsAreCreate, err := allSQLsAreCreateQueries(sqls, exec.parser)\n\t\tif err != nil {\n\t\t\treturn errorExecResult(err)\n\t\t}\n\t\tif !allSQLsAreCreate {\n\t\t\treturn errorExecResult(errors.New(\"--batch-size only allowed when all queries are CREATE TABLE|VIEW\"))\n\t\t}\n\n\t\tsqls = batchSQLs(sqls, int(exec.batchSize))\n\t}\n\tfor index, sql := range sqls {\n\t\t// Attempt to renew lease:\n\t\tif err := rl.Do(func() error { return topo.CheckKeyspaceLocked(ctx, exec.keyspace) }); err != nil {\n\t\t\treturn errorExecResult(vterrors.Wrapf(err, \"CheckKeyspaceLocked in ApplySchemaKeyspace %v\", exec.keyspace))","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/schemamanager/tablet_executor.go#L449-L485","documentation":"schemamanager's batch mode (--batch-size > 1) groups multiple SQL statements into one query per batch, which is only safe with the 'direct' DDL strategy that sends raw SQL to tablets. Non-direct strategies (e.g. gh-ost, pt-Online-Schema-Change) migrate one table per migration and cannot accept batched multi-statement SQL, so Execute rejects the combination up front.","triggerScenarios":"Running Execute (or ApplySchema) with --batch-size set greater than 1 while ddl_strategy is anything other than 'direct'.","commonSituations":"Operators combining --batch-size with gh-ost/pt-osc strategy in vtctld ApplySchema invocations; scripts that set a default batch size without pinning the strategy.","solutions":["Pass ddl_strategy=direct (e.g. --ddl-strategy direct) when using --batch-size","Remove --batch-size so each statement runs as its own migration","Split the DDL into CREATE-only statements and keep strategy direct if batching CREATE TABLEs"],"exampleFix":"// before\nvtctldclient ApplySchema --sql-file d.sql --batch-size 10 --ddl-strategy \"gh-ost\" ks\n// after\nvtctldclient ApplySchema --sql-file d.sql --batch-size 10 --ddl-strategy \"direct\" ks","handlingStrategy":"validation","validationCode":"if batchSize > 1 && !strings.Contains(ddlStrategy, \"direct\") {\n    return fmt.Errorf(\"--batch-size requires 'direct' ddl_strategy, got %q\", ddlStrategy)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"--batch-size requires 'direct'\") {\n    // fall back: drop batch-size or switch strategy to direct\n}","preventionTips":["Only combine --batch-size with --ddl-strategy direct","Validate flag combinations in wrapper scripts before invoking vtctldclient","Document strategy constraints wherever batch-size defaults are set"],"tags":["go","schemamanager","configuration","flags"],"backgroundTag":"incompatible-flag-combination","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}