bytebase/bytebase · error

failed to parse schema DDL

Error message

failed to parse schema DDL

What it means

After initializing the catalog, GetDatabaseMetadataOmni executes the whole schema DDL text through the embedded omni MySQL catalog with ContinueOnError. If the batch itself fails (e.g. the SQL cannot be parsed at all), the error is wrapped as 'failed to parse schema DDL'. This indicates the input is not valid MySQL DDL for the embedded parser.

Source

Thrown at backend/plugin/schema/mysql/get_database_metadata_omni.go:34

}

// GetDatabaseMetadataOmni parses MySQL schema DDL text and returns database metadata
// using the omni catalog. This replaces the ANTLR-based GetDatabaseMetadata.
func GetDatabaseMetadataOmni(schemaText string) (*storepb.DatabaseSchemaMetadata, error) {
	if schemaText == "" {
		return &storepb.DatabaseSchemaMetadata{}, nil
	}

	const dbName = "tmp"
	c := catalog.New()
	initSQL := fmt.Sprintf("SET foreign_key_checks = 0;\nCREATE DATABASE IF NOT EXISTS `%s`;\nUSE `%s`;", dbName, dbName)
	if _, err := c.Exec(initSQL, nil); err != nil {
		return nil, errors.Wrap(err, "failed to initialize catalog")
	}

	results, err := c.Exec(schemaText, &catalog.ExecOptions{ContinueOnError: true})
	if err != nil {
		return nil, errors.Wrap(err, "failed to parse schema DDL")
	}

	// Check for hard errors (not per-statement errors).
	for _, r := range results {
		if r.Error != nil {
			return nil, errors.Wrapf(r.Error, "failed to execute schema DDL")
		}
	}

	proto := catalogToProto(c, dbName)
	return proto, nil
}

View on GitHub (pinned to 1870550677)

Solutions

  1. Unwrap the error to find the offending statement and parser message.
  2. Validate the schemaText with mysql client or lint it as MySQL DDL before passing it in.
  3. Fix or regenerate the DDL so it is standard MySQL CREATE TABLE/VIEW/etc. syntax.
  4. If specific statements legitimately fail, rely on the per-statement results path (ContinueOnError) rather than the batch error and inspect results for r.Error.

Example fix

// before
proto, err := GetDatabaseMetadataOmni(ctx, rawDDL) // rawDDL contains dialect-specific syntax
// after
validated, err := lintAndNormalizeMySQLDDL(rawDDL)
if err != nil {
    return nil, err
}
proto, err := GetDatabaseMetadataOmni(ctx, validated)
Defensive patterns

Strategy: validation

Validate before calling

if err := validateMySQLDDL(schemaText); err != nil {
    return nil, fmt.Errorf("schemaText is not valid MySQL DDL: %w", err)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to parse schema DDL") {
    return nil, fmt.Errorf("input schema rejected by parser: %w", err)
}

Prevention

When it happens

Trigger: Calling GetDatabaseMetadataOmni with schemaText containing syntax the omni parser rejects, non-DDL statements, or malformed multi-statement input.

Common situations: Schema text produced by another tool with MySQL-incompatible syntax; dialect drift between the generator and the omni parser; truncated or concatenated DDL files.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/ad690ecbdd994404. Report an issue: GitHub.