caddyserver/caddy · warning

STEK gob corrupted: %v

Error message

STEK gob corrupted: %v

What it means

The distributed STEK provider persists session ticket keys to storage as a gob; loadSTEK gob-decodes the stored bytes and wraps decode failures as 'STEK gob corrupted'. Notably, a storage read error (including not-exist) is NOT wrapped, so this specifically means bytes existed but did not decode — corruption or an incompatible gob schema.

Source

Thrown at modules/caddytls/distributedstek/distributedstek.go:128

}

// Next returns a channel which transmits the latest session ticket keys.
func (s *Provider) Next(doneChan <-chan struct{}) <-chan [][32]byte {
	keysChan := make(chan [][32]byte)
	go s.rotate(doneChan, keysChan)
	return keysChan
}

func (s *Provider) loadSTEK() (distributedSTEK, error) {
	var sg distributedSTEK
	gobBytes, err := s.storage.Load(s.ctx, stekFileName)
	if err != nil {
		return sg, err // don't wrap, in case error is certmagic.ErrNotExist
	}
	dec := gob.NewDecoder(bytes.NewReader(gobBytes))
	err = dec.Decode(&sg)
	if err != nil {
		return sg, fmt.Errorf("STEK gob corrupted: %v", err)
	}
	return sg, nil
}

func (s *Provider) storeSTEK(dstek distributedSTEK) error {
	var buf bytes.Buffer
	err := gob.NewEncoder(&buf).Encode(dstek)
	if err != nil {
		return fmt.Errorf("encoding STEK gob: %v", err)
	}
	err = s.storage.Store(s.ctx, stekFileName, buf.Bytes())
	if err != nil {
		return fmt.Errorf("storing STEK gob: %v", err)
	}
	return nil
}

// getSTEK locks and loads the current STEK from storage. If none

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Delete the stored STEK object so a fresh key set is generated (the provider creates and persists new STEKs when none exists); for file storage remove the stek file under the storage root, then reload
  2. If it recurs, check storage durability (disk health, fsync behavior, network storage consistency)
  3. After a Caddy upgrade causing schema mismatch, a one-time deletion is expected and safe — old ticket keys are ephemeral by design

Example fix

# before: recurring 'STEK gob corrupted' at startup
ls /var/lib/caddy/storage/... # locate stek object

# after: remove it and reload Caddy
rm /var/lib/caddy/storage/<...>/stek  # path per your storage config
systemctl reload caddy
Defensive patterns

Strategy: fallback

Validate before calling

// Detect a corrupt STEK object before it breaks the provider
type distributedSTEK struct { Keys [][32]byte; NextRotation time.Time }
func stekLooksValid(b []byte) bool {
	var s struct { Keys [][32]byte; NextRotation time.Time }
	return gob.NewDecoder(bytes.NewReader(b)).Decode(&s) == nil && len(s.Keys) > 0
}

Try / catch

// Since loadSTEK does not wrap storage.ErrNotExist, treat decode failure as stale:
// delete the stored object so the provider mints fresh keys on next rotation.
// (shell)
rm "$CADDY_STORAGE_ROOT/.../stek" && systemctl reload caddy

Prevention

When it happens

Trigger: The stored stek file was truncated (e.g. crash during write), partially synced, or written by a different Caddy version whose distributedSTEK struct changed; manual tampering with the storage object.

Common situations: Crash or disk-full during a previous STEK write; upgrading Caddy across incompatible struct changes; copying storage buckets between environments mid-write.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/dea909c58f248e19. Report an issue: GitHub.