gohugoio/hugo · error
failed to acquire a build lock: %w
Error message
failed to acquire a build lock: %w
What it means
Before building, Hugo takes a file-based lock (via BaseFs.LockBuild) to prevent two Hugo processes from writing the same destination concurrently. This error means acquiring that lock file (.hugo_build.lock in the project root) failed — either another process holds it past the timeout or the lock file can't be created.
Source
Thrown at hugolib/hugo_sites_build.go:97
}
infol := h.Log.InfoCommand("build")
defer loggers.TimeTrackf(infol, time.Now(), nil, "")
defer func() {
h.reportProgress(func() (state terminal.ProgressState, progress float64) {
return terminal.ProgressHidden, 1.0
})
h.BuildState.BuildCounter.Add(1)
}()
if h.Deps == nil {
panic("must have deps")
}
if !config.NoBuildLock {
unlock, err := h.BaseFs.LockBuild()
if err != nil {
return fmt.Errorf("failed to acquire a build lock: %w", err)
}
defer unlock()
}
defer func() {
for _, s := range h.Sites {
s.Deps.BuildEndListeners.Notify()
}
}()
errCollector := h.StartErrorCollector()
errs := make(chan error)
go func(from, to chan error) {
var errors []error
i := 0
for e := range from {
i++View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Stop the other Hugo process using the same project (commonly a running `hugo server`).
- Delete a stale `.hugo_build.lock` in the project root if no other process is running.
- Ensure the project directory is writable by the build user.
- If concurrent builds are intentional and write to different destinations, pass `--noBuildLock`.
Defensive patterns
Strategy: retry
Validate before calling
// ensure only one build runs per HugoSites instance // serialize callers: guard Build() with your own queue if invoking concurrently
Try / catch
err := h.Build(cfg)
if err != nil && strings.Contains(err.Error(), "failed to acquire a build lock") {
// another build in flight; wait and retry once
time.Sleep(500 * time.Millisecond)
err = h.Build(cfg)
} Prevention
- Never call Build concurrently on the same HugoSites instance; serialize through a single goroutine or channel
- In server/watch mode let Hugo drive rebuilds instead of triggering them externally
- If embedding Hugo, wrap Build in your own mutex so lock contention surfaces in your code, not deep in the build
When it happens
Trigger: HugoSites.Build with config.NoBuildLock=false when another hugo build/server against the same source is running and holds .hugo_build.lock, when a crashed process left a stale lock, or when the project directory is read-only so the lock file cannot be created.
Common situations: Running `hugo` while `hugo server` is still up in another terminal; CI jobs building the same checkout in parallel; read-only mounted source directories in containers; stale .hugo_build.lock after an OOM-killed build.
Related errors
- error copying static files: %w
- failed to acquire a build lock: %s
- failed to save file %q:: %w
- failed to resolve output path %q: %w
- failed to copy %q to %q: %w
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/cdd888c605a1807c.json.
Report an issue: GitHub ↗.