juicedata/juicefs · critical

failed to set isolation level: %s

Error message

failed to set isolation level: %s

What it means

JuiceFS requires MySQL's isolation level to be settable to repeatable-read and probes with two system variable names (transaction_isolation for MySQL 5.7+/8.x, tx_isolation for older). If every probe's ping failed with 'unknown system variable' for all candidate keys, it gives up with this error, meaning the server is a dialect that supports neither variable or errors unexpectedly.

Source

Thrown at pkg/meta/sql_mysql.go:82

		cfg.Params[key] = "'repeatable-read'"
		engine, err = xorm.NewEngine("mysql", cfg.FormatDSN())
		if err != nil {
			return nil, fmt.Errorf("unable to create engine: %s", err)
		}

		if err = engine.Ping(); err == nil {
			return engine, nil
		}

		_ = engine.Close()
		delete(cfg.Params, key)

		if !isUnknownTransactionIsolationErr(err, key) {
			return nil, fmt.Errorf("ping database: %s", err)
		}
	}

	return nil, fmt.Errorf("failed to set isolation level: %s", err)
}

func isUnknownTransactionIsolationErr(err error, key string) bool {
	return err != nil && strings.Contains(strings.ToLower(err.Error()), fmt.Sprintf("unknown system variable '%s'", key))
}

func init() {
	dupErrorCheckers = append(dupErrorCheckers, isMySQLDuplicateEntryErr)
	engineCreator["mysql"] = createMySQLEngine
	Register("mysql", newSQLMeta)
}

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Connect directly to a real MySQL (or MariaDB ≥5.7 with tx_isolation) server instead of through the proxy that hides system variables.
  2. Verify with mysql client: SHOW VARIABLES LIKE 'tx_isolation'; and SHOW VARIABLES LIKE 'transaction_isolation'; — one must exist.
  3. Check the wrapped error text: it shows the last 'unknown system variable' message; confirm which dialect the server actually is.
  4. If the proxy is required, configure it to pass through system-variable queries, or use a JuiceFS metadata engine that doesn't need this (redis/sqlite).

Example fix

// before (proxy strips system variables)
juicefs mount "mysql://user:pass@tcp(proxy:6033)/jfs" /mnt/jfs
// after (point at the real MySQL backend)
juicefs mount "mysql://user:pass@tcp(mysql-primary:3306)/jfs" /mnt/jfs
Defensive patterns

Strategy: fallback

Validate before calling

out, _ := exec.Command("mysql", "-h", host, "-u", user, "-p"+pw, "-e", "SHOW VARIABLES LIKE 'tx_isolation'; SHOW VARIABLES LIKE 'transaction_isolation';").Output()
if len(out) == 0 { return fmt.Errorf("server exposes neither isolation variable; use a direct MySQL backend") }

Try / catch

if err := mountVol(); err != nil && strings.Contains(err.Error(), "failed to set isolation level") {
    log.Fatalf("server does not expose isolation variables — bypass proxy or switch engine: %v", err)
}

Prevention

When it happens

Trigger: Connecting to a MySQL-compatible server that rejects both `transaction_isolation` and `tx_isolation` system variables — e.g. certain proxies (ProxySQL variants), MariaDB forks, or serverless MySQL gateways that strip system variables.

Common situations: Pointing JuiceFS at an aggressive MySQL proxy or managed service that doesn't expose isolation variables; a custom middleware rewriting the handshake; very old or heavily modified MySQL builds.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/ed164961612dfbbe. Report an issue: GitHub.