golang-migrate/migrate · error

unable to parse option x-multi-statement: %w

Error message

unable to parse option x-multi-statement: %w

What it means

The x-multi-statement URL option for the pgx/v5 driver enables multiple SQL statements per migration. Its value is parsed with strconv.ParseBool, and Open fails with this error if the value is not a recognized boolean literal. Purely a client-side URL validation failure.

Source

Thrown at database/pgx/v5/pgx.go:191

		}
	}

	multiStatementMaxSize := DefaultMultiStatementMaxSize
	if s := purl.Query().Get("x-multi-statement-max-size"); len(s) > 0 {
		multiStatementMaxSize, err = strconv.Atoi(s)
		if err != nil {
			return nil, err
		}
		if multiStatementMaxSize <= 0 {
			multiStatementMaxSize = DefaultMultiStatementMaxSize
		}
	}

	multiStatementEnabled := false
	if s := purl.Query().Get("x-multi-statement"); len(s) > 0 {
		multiStatementEnabled, err = strconv.ParseBool(s)
		if err != nil {
			return nil, fmt.Errorf("unable to parse option x-multi-statement: %w", err)
		}
	}

	px, err := WithInstance(db, &Config{
		DatabaseName:          purl.Path,
		MigrationsTable:       migrationsTable,
		MigrationsTableQuoted: migrationsTableQuoted,
		StatementTimeout:      time.Duration(statementTimeout) * time.Millisecond,
		MultiStatementEnabled: multiStatementEnabled,
		MultiStatementMaxSize: multiStatementMaxSize,
	})

	if err != nil {
		return nil, err
	}

	return px, nil
}

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Use a valid ParseBool value: true/false (or 1/0, t/f, T/F, TRUE/FALSE)
  2. Remove x-multi-statement from the URL if multi-statement behavior is not needed (it defaults to false)
  3. Trim whitespace around the value — ' true' is not parseable
  4. Inspect the wrapped strconv error for the exact offending string

Example fix

// before
dsn := "postgres://u:p@host/db?x-multi-statement=on"
// after
dsn := "postgres://u:p@host/db?x-multi-statement=true"
Defensive patterns

Strategy: validation

Validate before calling

u, _ := url.Parse(dsn)
if v := u.Query().Get("x-multi-statement"); v != "" {
    if _, err := strconv.ParseBool(v); err != nil {
        return fmt.Errorf("invalid x-multi-statement %q: %w", v, err)
    }
}

Type guard

func isValidBool(v string) bool {
    _, err := strconv.ParseBool(v)
    return err == nil
}

Try / catch

if err := m.Up(); err != nil {
    if strings.Contains(err.Error(), "unable to parse option x-multi-statement") {
        log.Fatalf("DSN x-multi-statement must be a boolean literal: %v", err)
    }
    panic(err)
}

Prevention

When it happens

Trigger: Opening a pgx/v5 connection with a URL like postgres://user:pass@host/db?x-multi-statement=yes, =1.0, or any non-boolean string in x-multi-statement.

Common situations: Copying the option name but inventing the value ('yes', 'on'), templating engines injecting an empty or malformed value, or accidental duplication of the query parameter producing a concatenated string.

Understand the failure class

Related errors


AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02). Data as JSON: /api/errors/f2b8aa09ae1e84e1. Report an issue: GitHub.