juanfont/headscale · error · ErrInvalidJournalMode

%w: %s

Error message

%w: %s

What it means

Config.Validate rejected the configured SQLite journal_mode: the value is non-empty but not one of the valid JournalMode pragma values (WAL, DELETE, TRUNCATE, PERSIST, MEMORY, OFF). The sentinel ErrInvalidJournalMode is wrapped with the bad value. Journal mode controls write concurrency and crash recovery behavior.

Source

Thrown at hscontrol/db/sqliteconfig/config.go:322

	return &Config{
		Path:              ":memory:",
		WALAutocheckpoint: -1, // not set, use driver default
		ForeignKeys:       true,
	}
}

// Validate checks if all configuration values are valid.
func (c *Config) Validate() error {
	if c.Path == "" {
		return ErrPathEmpty
	}

	if c.BusyTimeout < 0 {
		return fmt.Errorf("%w, got %d", ErrBusyTimeoutNegative, c.BusyTimeout)
	}

	if c.JournalMode != "" && !c.JournalMode.IsValid() {
		return fmt.Errorf("%w: %s", ErrInvalidJournalMode, c.JournalMode)
	}

	if c.AutoVacuum != "" && !c.AutoVacuum.IsValid() {
		return fmt.Errorf("%w: %s", ErrInvalidAutoVacuum, c.AutoVacuum)
	}

	if c.WALAutocheckpoint < -1 {
		return fmt.Errorf("%w, got %d", ErrWALAutocheckpoint, c.WALAutocheckpoint)
	}

	if c.Synchronous != "" && !c.Synchronous.IsValid() {
		return fmt.Errorf("%w: %s", ErrInvalidSynchronous, c.Synchronous)
	}

	if c.TxLock != "" && !c.TxLock.IsValid() {
		return fmt.Errorf("%w: %s", ErrInvalidTxLock, c.TxLock)
	}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Use one of the exported constants: sqliteconfig.JournalModeWAL (recommended for production), JournalModeDelete, etc.
  2. If loading from a config file, strings.ToUpper the value before assignment.
  3. Leave it empty to accept the driver default.

Example fix

// before
cfg.JournalMode = sqliteconfig.JournalMode("wal") // fails IsValid()

// after
cfg.JournalMode = sqliteconfig.JournalModeWAL
Defensive patterns

Strategy: type-guard

Type guard

func validJournalMode(v sqliteconfig.JournalMode) bool {
    switch v {
    case sqliteconfig.JournalModeWAL,
        sqliteconfig.JournalModeDelete,
        sqliteconfig.JournalModeTruncate,
        sqliteconfig.JournalModePersist,
        sqliteconfig.JournalModeMemory,
        sqliteconfig.JournalModeOff:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Setting JournalMode to something like 'wal' (lowercase), 'WRITE_AHEAD', or 'default' in a sqliteconfig.Config and calling Validate/ToURL. Only exact uppercase pragma strings from the JournalMode constants pass IsValid().

Common situations: Lowercase values in YAML/TOML configs that were never uppercased; users copying pragma names from SQLite docs with different spelling; typos.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/1d67a2cda8b2f10a. Report an issue: GitHub.