dagger/dagger · error

wipe unclean persistence db: %w

Error message

wipe unclean persistence db: %w

What it means

After detecting an unclean shutdown, NewCache wipes the SQLite persistence files via wipeSQLiteFiles(dbPath) so the engine can cold-start with a fresh cache. If that deletion fails (permissions, file locks, read-only mount), this wrapped error aborts cache initialization.

Source

Thrown at dagql/cache.go:458

		c.pdb = persistDB
	}

	cleanShutdownVal, found, err := c.pdb.SelectMetaValue(ctx, persistdb.MetaKeyCleanShutdown)
	if err != nil {
		if closeErr := closeCacheDBs(db, c.pdb); closeErr != nil {
			return nil, errors.Join(fmt.Errorf("read clean_shutdown metadata: %w", err), closeErr)
		}
		return nil, fmt.Errorf("read clean_shutdown metadata: %w", err)
	}
	if found && cleanShutdownVal != "1" {
		c.persistenceResetReason = CachePersistenceResetUncleanShutdown
		c.tracePersistStoreWipedUncleanShutdown(ctx, cleanShutdownVal)
		slog.Warn("dagql persistence store marked unclean; wiping and cold-starting", "cleanShutdown", cleanShutdownVal)
		if closeErr := closeCacheDBs(db, c.pdb); closeErr != nil {
			return nil, errors.Join(fmt.Errorf("close db before wipe"), closeErr)
		}
		if err := wipeSQLiteFiles(dbPath); err != nil {
			return nil, fmt.Errorf("wipe unclean persistence db: %w", err)
		}

		db, persistDB, err = prepareCacheDBs(ctx, dbPath)
		if err != nil {
			return nil, err
		}
		c.sqlDB = db
		c.pdb = persistDB
	}
	if err := c.importPersistedState(ctx); err != nil {
		c.persistenceResetReason = CachePersistenceResetImportFailure
		c.tracePersistStoreWipedImportFailure(ctx, err)
		slog.Warn("dagql persistence import failed; wiping and cold-starting", "err", err)
		if closeErr := closeCacheDBs(db, c.pdb); closeErr != nil {
			return nil, errors.Join(fmt.Errorf("close db before import-wipe"), closeErr)
		}
		if err := wipeSQLiteFiles(dbPath); err != nil {
			return nil, fmt.Errorf("wipe persistence db after import failure: %w", err)

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Verify the cache volume is writable and has space (mount options, df).
  2. Ensure no other process holds the DB files open, then retry startup.
  3. Fix file ownership/permissions (chown/chmod) or remove immutable flags (chattr -i).
  4. Manually delete dbPath cache files while stopped and start the engine again.

Example fix

// before: crash leaves unclean DB on read-only volume
wipe unclean persistence db: permission denied
// after
$ sudo mount -o remount,rw /var/lib/dagger && rm -f /var/lib/dagger/cache.db*
Defensive patterns

Strategy: validation

Validate before calling

// before engine start, ensure the wipe is possible: writable dir, no leftover locks
func wipeable(dbPath string) error {
	if err := unix.Access(dbPath, unix.W_OK); err != nil { return err }
	for _, f := range []string{dbPath + "-wal", dbPath + "-shm"} {
		if err := os.Remove(f); err != nil && !os.IsNotExist(err) { return err }
	}
	return nil
}

Prevention

When it happens

Trigger: NewCache finds cleanShutdownVal != "1", successfully closes both DBs, then wipeSQLiteFiles(dbPath) fails to unlink the db/-wal/-shm files.

Common situations: Cache directory on a read-only or full volume after a crash; another process holding the deleted files open; immutable attribute or wrong ownership on cache files; container with a mounted cache dir lacking write access.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/cd156e324b508cc7. Report an issue: GitHub.