kopia/kopia · error

error writing pending content

Error message

error writing pending content

What it means

After waiting for in-flight packs, Flush calls finishAllPacksLocked to write all newly pending packs; this wrapper reports a failure there. It is essentially the same failure mode as 'error writing pack content' but raised from Flush's own finish step.

Solutions

  1. Unwrap the inner cause to identify preparation vs upload failure.
  2. Retry Flush after restoring storage access — pending packs are preserved until written.
  3. Review recent changes to format parameters (compression, index version).
  4. Avoid canceling the context mid-Flush; use WithoutCancel for shutdown flushes.

Example fix

// before: canceling flush on shutdown signal
ctx, cancel := context.WithCancel(...)
go func() { <-sig; cancel() }()
err := bm.Flush(ctx)
// after: keep flush alive through shutdown
err := bm.Flush(context.WithoutCancel(ctx))
if err != nil { log.Printf("deferred flush needed: %v", err) }
Defensive patterns

Strategy: retry

Try / catch

// Go: don't abort Close on transient flush failure; retry once
if err := bm.Flush(ctx); err != nil {
    err = bm.Flush(context.WithoutCancel(ctx))
}

Prevention

When it happens

Trigger: Flush() → (after waiting for writingPacks) → finishAllPacksLocked → writePackAndAddToIndexLocked fails for a pending pack: pack preparation, blob upload, or mutable-parameter errors.

Common situations: Storage errors occurring exactly at flush time (quota hit, network drop); invalid format parameters configured since the last flush; cancellation of ctx while many packs flush at once during Close().

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/a09efba919d18415. Report an issue: GitHub.

Appendix: source

Thrown at repo/content/content_manager.go:654

	fp := append([]*pendingPackInfo(nil), bm.failedPacks...)
	for _, pp := range fp {
		contentlog.Log1(ctx, bm.log, "retry-write", blobparam.BlobID("packBlobID", pp.packBlobID))

		if err := bm.writePackAndAddToIndexLocked(ctx, pp); err != nil {
			return errors.Wrap(err, "error writing previously failed pack")
		}
	}

	for len(bm.writingPacks) > 0 {
		contentlog.Log1(ctx, bm.log, "waiting for in-progress packs to finish", logparam.Int("len", len(bm.writingPacks)))

		// wait packs that are currently writing in other goroutines to finish
		bm.cond.Wait()
	}

	// finish all new pending packs
	if err := bm.finishAllPacksLocked(ctx); err != nil {
		return errors.Wrap(err, "error writing pending content")
	}

	if err := bm.flushPackIndexesLocked(ctx, mp); err != nil {
		return errors.Wrap(err, "error flushing indexes")
	}

	return nil
}

// RewriteContent causes reads and re-writes a given content using the most recent format.
// TODO(jkowalski): this will currently always re-encrypt and re-compress data, perhaps consider a
// pass-through mode that preserves encrypted/compressed bits.
func (bm *WriteManager) RewriteContent(ctx context.Context, contentID ID) error {
	contentlog.Log1(ctx, bm.log, "rewrite-content",
		contentparam.ContentID("contentID", contentID))

	mp, mperr := bm.format.GetMutableParameters(ctx)
	if mperr != nil {

View on GitHub (pinned to 82495e54b5)