golang-migrate/migrate · error

x-no-tx-wrap: %s

Error message

x-no-tx-wrap: %s

What it means

The sqlite driver's Open parses the x-no-tx-wrap URL query parameter as a boolean (strconv.ParseBool) to decide whether migrations run outside a transaction. A present-but-invalid value causes Open to return fmt.Errorf("x-no-tx-wrap: %s", err), embedding the parse error and offending value. Valid values are Go's recognized booleans: 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.

Source

Thrown at database/sqlite/sqlite.go:112

	}
	dbfile := strings.Replace(migrate.FilterCustomQuery(purl).String(), "sqlite://", "", 1)
	db, err := sql.Open("sqlite", dbfile)
	if err != nil {
		return nil, err
	}

	qv := purl.Query()

	migrationsTable := qv.Get("x-migrations-table")
	if len(migrationsTable) == 0 {
		migrationsTable = DefaultMigrationsTable
	}

	noTxWrap := false
	if v := qv.Get("x-no-tx-wrap"); v != "" {
		noTxWrap, err = strconv.ParseBool(v)
		if err != nil {
			return nil, fmt.Errorf("x-no-tx-wrap: %s", err)
		}
	}

	mx, err := WithInstance(db, &Config{
		DatabaseName:    purl.Path,
		MigrationsTable: migrationsTable,
		NoTxWrap:        noTxWrap,
	})
	if err != nil {
		return nil, err
	}
	return mx, nil
}

func (m *Sqlite) Close() error {
	return m.db.Close()
}

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Use a strconv.ParseBool-accepted value: true/TRUE/True/t/T/1 or false/FALSE/False/f/F/0.
  2. Omit x-no-tx-wrap entirely to keep the default transaction-wrapped behavior.
  3. Trim whitespace and quotes from the DSN before passing it to migrate.Open/sql.Open.

Example fix

// before
dsn := "sqlite://data/app.db?x-no-tx-wrap=on" // parse error
// after
dsn := "sqlite://data/app.db?x-no-tx-wrap=1"
Defensive patterns

Strategy: validation

Validate before calling

if v := q.Get("x-no-tx-wrap"); v != "" {
    if _, err := strconv.ParseBool(v); err != nil {
        return fmt.Errorf("invalid x-no-tx-wrap %q: use 1/t/true or 0/f/false", v)
    }
}

Type guard

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

Try / catch

d, err := sqlite.Open(dsn)
if err != nil {
    if strings.HasPrefix(err.Error(), "x-no-tx-wrap:") {
        return fmt.Errorf("fix DSN boolean param (allowed: 1,t,true,0,f,false): %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Opening with a URL like sqlite://app.db?x-no-tx-wrap=on (or "yes", "Y", " true") — the parameter is present and non-empty but strconv.ParseBool rejects it.

Common situations: Human-style booleans ("yes"/"on") in the DSN copied from other tools' docs; shell/env quoting or whitespace contaminating the connection string; templated DSNs where the flag value is substituted from a non-boolean config.

Related errors


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