{"record":{"id":"6cd95d05c4226f22","repo":"argoproj/argo-workflows","slug":"invalid-mysql-config-options-w","errorCode":null,"errorMessage":"invalid MySQL config options: %w","messagePattern":"invalid MySQL config options: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/sqldb/sqldb.go","lineNumber":279,"sourceCode":"\tmysqlCfg := mysql.NewConfig()\n\tmysqlCfg.User = username\n\tmysqlCfg.Passwd = password\n\tmysqlCfg.Net = \"tcp\"\n\tmysqlCfg.Addr = cfg.GetHostname()\n\tmysqlCfg.DBName = cfg.Database\n\tmysqlCfg.ParseTime = true\n\tmysqlCfg.AllowNativePasswords = true // Required for MariaDB which uses mysql_native_password by default\n\tmysqlCfg.Params = cfg.Options\n\tmysqlCfg.Timeout = connectTimeout\n\t// cfg.Options mixes driver-level DSN options (tls, readTimeout, ...) with\n\t// server system variables. NewConnector consumes the config directly, and the\n\t// driver only interprets driver-level options when parsing a DSN — left in\n\t// Params they would be sent to the server as SET statements instead (e.g.\n\t// leaving TLS disabled). Round-trip through FormatDSN/ParseDSN so options are\n\t// interpreted the same way DSN-opened sessions always interpreted them.\n\tparsedCfg, err := mysql.ParseDSN(mysqlCfg.FormatDSN())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid MySQL config options: %w\", err)\n\t}\n\treturn parsedCfg, nil\n}\n\nfunc createMySQLDBSessionWithCreds(cfg *config.MySQLConfig, persistPool *config.ConnectionPool, username, password string, connectTimeout time.Duration) (db.Session, error) {\n\tmysqlCfg, err := buildMySQLConfig(cfg, username, password, connectTimeout)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Wrap the MySQL connector so Connect (dial + handshake read) is bounded by\n\t// connectTimeout, protecting against a half-open server the same way lib/pq's\n\t// connect_timeout protects PostgreSQL.\n\tconnector, err := mysql.NewConnector(mysqlCfg)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create mysql connector: %w\", err)\n\t}\n\twrapped := &timeoutConnector{Connector: connector, timeout: connectTimeout}","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/util/sqldb/sqldb.go#L261-L297","documentation":"buildMySQLConfig round-trips the constructed mysql.Config through mysql.ParseDSN(mysqlCfg.FormatDSN()) so driver-level options are interpreted at the driver layer rather than sent to the server as SET statements. If FormatDSN produces a DSN that go-sql-driver/mysql's ParseDSN rejects, this 'invalid MySQL config options' error is returned wrapping the parse error.","triggerScenarios":"createMySQLDBSessionWithCreds calls buildMySQLConfig with a MySQLConfig whose fields (address, params, timeout values, driver options) produce an unparseable DSN — e.g. invalid parameter names/values in Params, malformed address, or an option ParseDSN cannot interpret.","commonSituations":"Users add arbitrary keys under the MySQL 'params' or driver-options section of the configmap that go-sql-driver does not accept; bad time.Duration values for timeouts; copy-pasted DSN fragments placed into structured config fields; version upgrades where go-sql-driver tightened option validation.","solutions":["Look at the wrapped ParseDSN error text — it names the offending DSN key or value; remove or correct that key in the MySQL config.","Validate each MySQL configmap field against the documented MySQLConfig schema; put only go-sql-driver-supported parameters in params/driver options.","If you need custom driver options, confirm they are valid DSN parameters for your go-sql-driver version (e.g. tls=true, allowNativePasswords).","Test the equivalent DSN directly with mysql.ParseDSN or by connecting with the mysql CLI using the same options."],"exampleFix":"// before\nmysql:\n  params:\n    sslmode: require     # not a go-sql-driver option -> ParseDSN error\n// after\nmysql:\n  options:\n    tls: true            # driver-level option, accepted by ParseDSN","handlingStrategy":"validation","validationCode":"// sanity-check config before calling CreateDBSessionWithCreds\nif cfg.Host == \"\" || cfg.Port == 0 { return errors.New(\"mysql host/port required\") }\nfor k := range cfg.Params {\n    if !allowedDSNParams[k] { return fmt.Errorf(\"unsupported mysql param: %s\", k) }\n}","typeGuard":null,"tryCatchPattern":"session, err := CreateDBSessionWithCreds(ctx)\nif err != nil && strings.Contains(err.Error(), \"invalid MySQL config options\") {\n    // log full wrapped error; fail fast with actionable config message\n    logger.Error(ctx, \"mysql config rejected by driver\", err)\n    return err\n}","preventionTips":["Only use parameters documented for go-sql-driver/mysql in the mysql config section.","Lint the controller configmap with the project's config schema before rollout.","Test DSNs with a small program calling mysql.ParseDSN before deploying.","After driver upgrades, re-verify all driver-level options."],"tags":["database","mysql","config","dsn"],"backgroundTag":"invalid-database-dsn","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}