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
- 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
- Verify no stale act process still holds the bolt file lock (lsof ~/.cache/act/*.db)
- Move the cache dir off NFS/network storage to a local filesystem
- 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
- Give each concurrent act run its own cache directory
- Keep the cache dir on a local filesystem, never NFS
- Treat cache as disposable: delete the dir on any corruption and let it rebuild
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.