gohugoio/hugo · error

failed to acquire a build lock

Error message

failed to acquire a build lock: %w

What it means

Returned at the very start of a build when LockBuild() cannot acquire the build mutex. The %w is the lock-acquisition error from the buildMu (a file/OS-level lock guarding the working tree).

Solutions

  1. Ensure no other Hugo process is running against the same project (check `ps` / `hugo --renderSegments` locks).
  2. Make the resources/ and working directories writable (chmod/chown).
  3. Remove a stale lock file under resources/_gen or the build lock path, then rebuild.
  4. If running embedded, pass NoBuildLock=true only for non-overlapping single-process builds.

Example fix

// before: two concurrent builds on same workdir
go func(){ _ = hugo.Build(cfg) }()
hugo.Build(cfg)  // -> failed to acquire a build lock

// after: serialize builds or disable the lock for single-process use
hugo.Build(BuildCfg{NoBuildLock: true})
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the work dir + resources are writable and no other Hugo process holds the lock.
if !writable(h.workingDir) { return errors.New("workdir not writable") }
if otherHugoRunning() { return errors.New("another hugo build is running") }

Try / catch

unlock, err := h.BaseFs.LockBuild()
if err != nil {
    if isLockHeld(err) { return fmt.Errorf("build in progress; retry later") }
    return fmt.Errorf("failed to acquire a build lock: %w", err)
}
defer unlock()

Prevention

When it happens

Trigger: Raised at hugo_sites_build.go:97 when h.BaseFs.LockBuild() fails (b.buildMu.Lock() errors). Occurs if the lock file backing buildMu cannot be created/acquired — e.g. resources dir not writable, or a stale/corrupt lock.

Common situations: Concurrent `hugo`/`hugo server`/`hugo mod` processes racing the same project; resources/ or working dir on a read-only filesystem; a previous crashed build left a stale lock; permissions changed in CI.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/cdd888c605a1807c. Report an issue: GitHub.

Appendix: 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 52c9bd7908)