ipfs/kubo · error
repo is closed
Error message
repo is closed
What it means
FSRepo.Close returns this when the repo has already been closed (r.closed is true). The repo tracks a closed flag guarded by packageLock, and any Close after the first is rejected. It is a lifecycle misuse signal: close once, in one place.
Source
Thrown at repo/fsrepo/fsrepo.go:544
func (r *FSRepo) readSpec() (string, error) {
fn, err := config.Path(r.path, specFn)
if err != nil {
return "", err
}
b, err := os.ReadFile(fn)
if err != nil {
return "", err
}
return strings.TrimSpace(string(b)), nil
}
// Close closes the FSRepo, releasing held resources.
func (r *FSRepo) Close() error {
packageLock.Lock()
defer packageLock.Unlock()
if r.closed {
return errors.New("repo is closed")
}
err := os.Remove(filepath.Join(r.path, apiFile))
if err != nil && !os.IsNotExist(err) {
log.Warn("error removing api file: ", err)
}
err = os.Remove(filepath.Join(r.path, gatewayFile))
if err != nil && !os.IsNotExist(err) {
log.Warn("error removing gateway file: ", err)
}
if err := r.ds.Close(); err != nil {
return err
}
// This code existed in the previous versions, but
// EventlogComponent.Close was never called. Preserving hereView on GitHub (pinned to 329838acdf)
Solutions
- Track whether your code already closed the repo before calling Close again
- Use sync.Once around the Close call
- Route all shutdown through a single owner function so Close is called exactly once
Example fix
// before
repo.Close()
defer repo.Close()
// after
var closeOnce sync.Once
close := func() { closeOnce.Do(func() { repo.Close() }) }
close()
defer close() Defensive patterns
Strategy: try-catch
Validate before calling
// track state yourself
if repoAlreadyClosed { return nil } Try / catch
if err := repo.Close(); err != nil {
if err.Error() == "repo is closed" { return nil } // already closed
return err
} Prevention
- Wrap Close in sync.Once
- Keep a single owner of the repo lifecycle
- Never call Close from both defer and explicit paths
When it happens
Trigger: Calling Close() twice on the same *FSRepo, e.g. explicit Close followed by a deferred Close in a cleanup path, or a shutdown handler racing a deferred close.
Common situations: Daemon shutdown code and tests that defer fsrepo.Close() while also calling it explicitly; wrapping a repo in a struct with its own Close that delegates to FSRepo.Close and is invoked by two owners.
Related errors
- cannot access config, repo not open
- ipfs not initialized, please run 'ipfs init'
- reading repo config: %w
- failed to initialize ephemeral node: %s
- assets: could load Asset '%s': %s
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/9ba4904dd7e09cff.
Report an issue: GitHub.