nektos/act · error

find cache: %w

Error message

find cache: %w

What it means

findCache queries the embedded bolthold/bolt database for a cache entry matching a key (exact match first). This error means the exact-match query failed with a real database error (not bolthold.ErrNotFound, which is handled by falling through to the prefix-regex lookup). Typical causes are a corrupted .db file, a bolt database locked by another process, or an unusable index inside the cache DB.

Source

Thrown at pkg/artifactcache/handler.go:382

	return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
		h.logger.Debugf("%s %s", r.Method, r.RequestURI)
		handler(w, r, params)
		go h.gcCache()
	}
}

// if not found, return (nil, nil) instead of an error.
func findCache(db *bolthold.Store, keys []string, version string) (*Cache, error) {
	cache := &Cache{}
	for _, prefix := range keys {
		// if a key in the list matches exactly, don't return partial matches
		if err := db.FindOne(cache,
			bolthold.Where("Key").Eq(prefix).
				And("Version").Eq(version).
				And("Complete").Eq(true).
				SortBy("CreatedAt").Reverse()); err == nil || !errors.Is(err, bolthold.ErrNotFound) {
			if err != nil {
				return nil, fmt.Errorf("find cache: %w", err)
			}
			return cache, nil
		}
		prefixPattern := fmt.Sprintf("^%s", regexp.QuoteMeta(prefix))
		re, err := regexp.Compile(prefixPattern)
		if err != nil {
			continue
		}
		if err := db.FindOne(cache,
			bolthold.Where("Key").RegExp(re).
				And("Version").Eq(version).
				And("Complete").Eq(true).
				SortBy("CreatedAt").Reverse()); err != nil {
			if errors.Is(err, bolthold.ErrNotFound) {
				continue
			}
			return nil, fmt.Errorf("find cache: %w", err)
		}

View on GitHub (pinned to 4f41128141)

Solutions

  1. Stop other act runs using the same cache dir, then delete ~/.cache/act (or the configured ACT_CACHE_SERVER_DIR) so a fresh DB is created
  2. Verify no stale act process still holds the bolt file lock (lsof ~/.cache/act/*.db)
  3. Move the cache dir off NFS/network storage to a local filesystem
  4. If it recurs, capture the wrapped bolthold error text — 'database is locked' vs 'invalid database' points to concurrency vs corruption
Defensive patterns

Strategy: fallback

Validate before calling

// Before starting parallel runs, ensure cache dir ownership
if fi, err := os.Stat(cacheDir); err == nil && fi.IsDir() {
    // check no other act holds the db lock
    if out, _ := exec.Command("lsof", filepath.Join(cacheDir, "actcache.db")).Output(); len(out) > 0 {
        log.Warn("cache db already open by another process")
    }
}

Try / catch

err := dbFind(...)
if err != nil {
    if errors.Is(err, bolthold.ErrNotFound) { /* miss, rebuild */ }
    else { log.Warnf("cache lookup failed, treating as miss: %v", err); /* serve without cache */ }
}

Prevention

When it happens

Trigger: Calling the artifact cache handler's lookup path (handler.go:193, i.e. any actions/cache 'restore' request hitting the local cache server) while the bolthold store under ~/.cache/act/.cache.db is locked by a concurrent act run, was killed mid-write, or has a stale/corrupt index for the Key/Version/Complete query.

Common situations: Two act instances sharing the same host cache dir; a previous act process was SIGKILLed during cache write leaving a torn bolt transaction; the cache directory is on a filesystem that does not support bolt's flock (NFS/network mounts); disk full during a prior insert.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/24df1e794c934887. Report an issue: GitHub.