golang-migrate/migrate · error
could not parse x-statement-timeout as float: %w
Error message
could not parse x-statement-timeout as float: %w
What it means
The MySQL driver accepts an optional x-statement-timeout custom parameter, parsed as an integer with strconv.Atoi. If the value is present but not a valid integer, Open returns this error wrapping the parse failure. Note the message says 'as float' but the code actually requires an integer — fractional values like '1.5' will fail.
Source
Thrown at database/mysql/mysql.go:250
customParams, err := extractCustomQueryParams(config)
if err != nil {
return nil, err
}
noLockParam, noLock := customParams["x-no-lock"], false
if noLockParam != "" {
noLock, err = strconv.ParseBool(noLockParam)
if err != nil {
return nil, fmt.Errorf("could not parse x-no-lock as bool: %w", err)
}
}
statementTimeoutParam := customParams["x-statement-timeout"]
statementTimeout := 0
if statementTimeoutParam != "" {
statementTimeout, err = strconv.Atoi(statementTimeoutParam)
if err != nil {
return nil, fmt.Errorf("could not parse x-statement-timeout as float: %w", err)
}
}
db, err := sql.Open("mysql", config.FormatDSN())
if err != nil {
return nil, err
}
mx, err := WithInstance(db, &Config{
DatabaseName: config.DBName,
MigrationsTable: customParams["x-migrations-table"],
NoLock: noLock,
StatementTimeout: time.Duration(statementTimeout) * time.Millisecond,
})
if err != nil {
return nil, err
}
View on GitHub (pinned to 01a9643f14)
Solutions
- Set x-statement-timeout to a plain integer (seconds), e.g. x-statement-timeout=5
- Remove the parameter if no statement timeout is wanted (it defaults to 0, i.e. disabled)
- Strip units/fractional parts in code before composing the URL
Example fix
// before url := "mysql://user:pass@tcp(db:3306)/app?x-statement-timeout=500ms" // after url := "mysql://user:pass@tcp(db:3306)/app?x-statement-timeout=5"
Defensive patterns
Strategy: validation
Validate before calling
if v := params.Get("x-statement-timeout"); v != "" {
if _, err := strconv.Atoi(v); err != nil {
return fmt.Errorf("x-statement-timeout must be an integer (seconds), got %q", v)
}
} Try / catch
drv, err := mysql.Open(dsn)
if err != nil && strings.Contains(err.Error(), "could not parse x-statement-timeout") {
return fmt.Errorf("x-statement-timeout must be a plain integer, no units or decimals: %w", err)
} Prevention
- Pass whole seconds as an integer; never attach units (ms/s) or decimals
- Treat the value as int in your config structs, not string/duration
- Validate with strconv.Atoi before composing the URL
When it happens
Trigger: Calling Open with a mysql:// URL containing x-statement-timeout set to a non-integer string, e.g. x-statement-timeout=500ms, x-statement-timeout=1.5, or an empty-but-present templated value (database/mysql/mysql.go:248-253).
Common situations: Developers copy duration syntax from other drivers (e.g. Postgres statement_timeout in ms with units); templating substitutes a decimal default; confusion with the message text leads to trying floats, which also fail because Atoi is used.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- could not parse x-no-lock as bool: %w
- to use TLS client authentication, both x-tls-cert and x-tls-
- no database name
- unable to parse option x-migrations-table-quoted: %w
- x-migrations-table must be quoted (for instance '"migrate"."
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/a11eb6c3634f8b59.
Report an issue: GitHub.