{"record":{"id":"a11eb6c3634f8b59","repo":"golang-migrate/migrate","slug":"could-not-parse-x-statement-timeout-as-float-w","errorCode":null,"errorMessage":"could not parse x-statement-timeout as float: %w","messagePattern":"could not parse x-statement-timeout as float: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"database/mysql/mysql.go","lineNumber":250,"sourceCode":"\tcustomParams, err := extractCustomQueryParams(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnoLockParam, noLock := customParams[\"x-no-lock\"], false\n\tif noLockParam != \"\" {\n\t\tnoLock, err = strconv.ParseBool(noLockParam)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse x-no-lock as bool: %w\", err)\n\t\t}\n\t}\n\n\tstatementTimeoutParam := customParams[\"x-statement-timeout\"]\n\tstatementTimeout := 0\n\tif statementTimeoutParam != \"\" {\n\t\tstatementTimeout, err = strconv.Atoi(statementTimeoutParam)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse x-statement-timeout as float: %w\", err)\n\t\t}\n\t}\n\n\tdb, err := sql.Open(\"mysql\", config.FormatDSN())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmx, err := WithInstance(db, &Config{\n\t\tDatabaseName:     config.DBName,\n\t\tMigrationsTable:  customParams[\"x-migrations-table\"],\n\t\tNoLock:           noLock,\n\t\tStatementTimeout: time.Duration(statementTimeout) * time.Millisecond,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/golang-migrate/migrate/blob/01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a/database/mysql/mysql.go#L232-L268","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nurl := \"mysql://user:pass@tcp(db:3306)/app?x-statement-timeout=500ms\"\n// after\nurl := \"mysql://user:pass@tcp(db:3306)/app?x-statement-timeout=5\"","handlingStrategy":"validation","validationCode":"if v := params.Get(\"x-statement-timeout\"); v != \"\" {\n    if _, err := strconv.Atoi(v); err != nil {\n        return fmt.Errorf(\"x-statement-timeout must be an integer (seconds), got %q\", v)\n    }\n}","typeGuard":null,"tryCatchPattern":"drv, err := mysql.Open(dsn)\nif err != nil && strings.Contains(err.Error(), \"could not parse x-statement-timeout\") {\n    return fmt.Errorf(\"x-statement-timeout must be a plain integer, no units or decimals: %w\", err)\n}","preventionTips":["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"],"tags":["mysql","configuration","numeric-parsing","url-parameters"],"backgroundTag":"invalid-numeric-parameter","analyzedSha":"01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a","analyzedAt":"2026-09-02T19:38:29.671Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}