benbjohnson/litestream · error

decode lock file

Error message

decode lock file: %w

What it means

The lease JSON downloaded from S3 could not be decoded — the lock file object exists but does not contain valid litestream.Lease JSON. The lease file was manually written, truncated, or written by an incompatible version.

Solutions

  1. Delete the malformed lease object from S3 and let litestream re-acquire
  2. Ensure only compatible litestream versions share the lease path
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at s3/leaser.go:219 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/631fec1fe51b6b2e. Report an issue: GitHub.

Appendix: source

Thrown at s3/leaser.go:219

func (l *Leaser) readLease(ctx context.Context) (*litestream.Lease, string, error) {
	key := l.lockKey()

	out, err := l.s3.GetObject(ctx, &s3.GetObjectInput{
		Bucket: aws.String(l.Bucket),
		Key:    aws.String(key),
	})
	if err != nil {
		if isNotExists(err) || isNotFoundError(err) {
			return nil, "", os.ErrNotExist
		}
		return nil, "", fmt.Errorf("get lock file: %w", err)
	}
	defer out.Body.Close()

	var lease litestream.Lease
	if err := json.NewDecoder(out.Body).Decode(&lease); err != nil {
		return nil, "", fmt.Errorf("decode lock file: %w", err)
	}

	etag := ""
	if out.ETag != nil {
		etag = *out.ETag
	}
	lease.ETag = etag

	return &lease, etag, nil
}

func (l *Leaser) writeLease(ctx context.Context, lease *litestream.Lease, etag string) (string, error) {
	key := l.lockKey()

	data, err := json.Marshal(lease)
	if err != nil {
		return "", fmt.Errorf("marshal lock file: %w", err)
	}

View on GitHub (pinned to 4ed7a308f6)