{"record":{"id":"894c7b08019c6b70","repo":"vitessio/vitess","slug":"error-parsing-vschema-statement-s-not-a-ddl-st","errorCode":null,"errorMessage":"error parsing vschema statement `%s`: not a ddl statement","messagePattern":"error parsing vschema statement `(.+?)`: not a ddl statement","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/vtctl.go","lineNumber":3379,"sourceCode":"\t\treturn errors.New(\"one of the --sql, --sql_file, --vschema, or --vschema_file flags must be specified when calling the ApplyVSchema command\")\n\t}\n\n\tif sqlMode {\n\t\tif *sqlFile != \"\" {\n\t\t\tsqlBytes, err := os.ReadFile(*sqlFile)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t*sql = string(sqlBytes)\n\t\t}\n\n\t\tstmt, err := wr.SQLParser().Parse(*sql)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing vschema statement `%s`: %v\", *sql, err)\n\t\t}\n\t\tddl, ok := stmt.(*sqlparser.AlterVschema)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"error parsing vschema statement `%s`: not a ddl statement\", *sql)\n\t\t}\n\n\t\tksvs, err = topotools.ApplyVSchemaDDL(ctx, keyspace, wr.TopoServer(), ddl)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\t// json mode\n\t\tvar schema []byte\n\t\tif *vschemaFile != \"\" {\n\t\t\tvar err error\n\t\t\tschema, err = os.ReadFile(*vschemaFile)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tschema = []byte(*vschema)\n\t\t}","sourceCodeStart":3361,"sourceCodeEnd":3397,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/vtctl.go#L3361-L3397","documentation":"The statement parsed successfully but is not an *sqlparser.AlterVschema node, so ApplyVSchemaDDL cannot process it. Only `ALTER VSCHEMA ...` statements are valid for this command path. This guards the type-asserted DDL before mutating the keyspace VSchema.","triggerScenarios":"Passing a valid SQL statement that is not `ALTER VSCHEMA` (e.g. `CREATE TABLE`, `SELECT`, or `ALTER KEYSPACE`) to a vschema update command.","commonSituations":"Copy-pasting normal MySQL DDL into the vschema editor; using `CREATE VINDEX` syntax from older Vitess instead of the current `ALTER VSCHEMA ADD VINDEX` form.","solutions":["Rewrite the statement to start with `ALTER VSCHEMA`","Convert legacy `CREATE VINDEX`/`ADD VINDEX` statements to the `ALTER VSCHEMA ADD VINDEX` form","Use the JSON vschema format via the topo directly if you need non-DDL updates"],"exampleFix":"// before\nsql := `CREATE VINDEX hash USING hash WITH num_buckets=8`\n// after\nsql := `ALTER VSCHEMA ADD VINDEX hash USING hash WITH num_buckets=8`","handlingStrategy":"type-guard","validationCode":"stmt, err := sqlparser.Parse(sql)\nif err != nil { return err }\nif _, ok := stmt.(*sqlparser.AlterVschema); !ok {\n\treturn errors.New(\"statement must be ALTER VSCHEMA ...\")\n}","typeGuard":"func isAlterVschema(stmt sqlparser.Statement) bool {\n\t_, ok := stmt.(*sqlparser.AlterVschema)\n\treturn ok\n}","tryCatchPattern":"if err := applyVSchema(sql); err != nil {\n\tif strings.HasSuffix(err.Error(), \"not a ddl statement\") {\n\t\treturn fmt.Errorf(\"rewrite %q as ALTER VSCHEMA ...\", sql)\n\t}\n\treturn err\n}","preventionTips":["Migrate legacy CREATE VINDEX statements to ALTER VSCHEMA form","Lint vschema files to require the ALTER VSCHEMA prefix","Document in runbooks that vschema commands only accept AlterVschema DDL"],"tags":["vtctl","vschema","sqlparser","go"],"backgroundTag":"not-a-ddl-statement","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}