semaphoreui/semaphore · error

read option

Error message

read option: %w

What it means

Returned by loadOrCreateJWTKey in util/jwt.go when the underlying OptionStore fails to read the jwt_signing_key option row from the database. It is a thin wrapping guard around store.GetOption: the %w carries the actual database error (connection failure, missing table, query error), and only the read step is affected — key decryption or generation happens in later branches.

Solutions

  1. Check the wrapped error for the concrete DB failure (connection refused, table missing, timeout)
  2. Verify database connectivity and that migrations ran so the options table exists
  3. Retry service startup after the database is reachable — a transient outage at boot is a common cause
  4. Ensure the service's DB user has SELECT permission on the options table
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at util/jwt.go:79 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07). Data as JSON: /api/errors/6268223df07409e8. Report an issue: GitHub.

Appendix: source

Thrown at util/jwt.go:79

			fmt.Fprintf(os.Stderr, "jwt: invalid jwt_max_ttl %q, falling back to 24h: %v\n", Config.JWT.MaxTTL, err)
		}
	}

	return jwt.SignerOptions{
		Issuer:     Config.JWT.Issuer,
		DefaultTTL: ttl,
		MaxTTL:     maxTTL,
	}
}

// loadOrCreateJWTKey returns the raw PEM bytes of the JWT signing key. It
// reads the encrypted value from the database, decrypts it, and returns the
// plaintext PEM. If no key exists yet it generates one, persists it, and
// returns the plaintext PEM.
func loadOrCreateJWTKey(store OptionStore) ([]byte, error) {
	stored, err := store.GetOption(jwtSigningKeyOption)
	if err != nil {
		return nil, fmt.Errorf("read option: %w", err)
	}

	if stored != "" {
		return decryptJWTKey(stored)
	}

	// No key in DB yet
	pemBytes, err := jwt.GenerateKeyPEM()
	if err != nil {
		return nil, err
	}

	encrypted, err := encryptJWTKey(pemBytes)
	if err != nil {
		return nil, err
	}

	if err := store.SetOption(jwtSigningKeyOption, encrypted); err != nil {

View on GitHub (pinned to 1774ccb71a)