gohugoio/hugo · error

failled to create base cache directory: %s

Error message

failled to create base cache directory: %s

What it means

On first use, each file cache lazily creates its base directory via `c.Fs.MkdirAll("", 0o777)` inside a `sync.Once`. If that mkdir fails (and the failure isn't 'already exists'), the error is stored as `initErr` and returned from every subsequent cache operation, so all reads/writes through that cache fail with this message (note the upstream typo 'failled').

Source

Thrown at cache/filecache/filecache.go:111

	afero.File
	unlock func()
}

func (l *lockedFile) Close() error {
	defer l.unlock()
	return l.File.Close()
}

func (c *Cache) init() error {
	if c == nil {
		panic("cache is nil")
	}

	c.initOnce.Do(func() {
		c.isInited = true
		// Create the base dir if it does not exist.
		if err := c.Fs.MkdirAll("", 0o777); err != nil && !os.IsExist(err) {
			err = fmt.Errorf("failled to create base cache directory: %s", err)
			c.initErr = err
		}
	})
	return c.initErr
}

// WriteCloser returns a transactional writer into the cache.
// It's important that it's closed when done.
func (c *Cache) WriteCloser(id string) (ItemInfo, io.WriteCloser, error) {
	if err := c.init(); err != nil {
		return ItemInfo{}, nil, err
	}

	id = cleanID(id)
	c.entryLocker.Lock(id)

	info := ItemInfo{Name: id}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Point the cache at a writable location: set `HUGO_CACHEDIR=/tmp/hugo_cache` or `cacheDir` in config to a directory the build user can create.
  2. Fix permissions/ownership on the existing cache root (`chown`/`chmod` the directory).
  3. In containers, mount a writable volume for the cache dir or run the build with a writable `$TMPDIR`.

Example fix

# before (CI container, read-only home)
hugo --minify
# after
export HUGO_CACHEDIR=/tmp/hugo_cache
hugo --minify
Defensive patterns

Strategy: validation

Validate before calling

# Verify the configured cache directory's parent is writable:
CACHE=${HUGO_CACHEDIR:-$(hugo config | sed -n 's/^cachedir *= *//p')}
mkdir -p "$CACHE" && test -w "$CACHE"

Try / catch

if err := build(); err != nil {
    if strings.Contains(err.Error(), "create base cache directory") {
        log.Println("set HUGO_CACHEDIR to a writable path")
    }
    return err
}

Prevention

When it happens

Trigger: Any cache access (`WriteCloser`, `GetOrCreate`, `ReadOrCreate`) whose lazy `init()` runs `MkdirAll` on the cache's base path and gets a permission, read-only-filesystem, or disk-full error — the cache root derives from `cacheDir` config, `HUGO_CACHEDIR`, or the platform default (e.g. `$TMPDIR/hugo_cache`).

Common situations: Docker/CI containers running as non-root with `cacheDir` pointing at an unwritable path; read-only root filesystems (Kubernetes `readOnlyRootFilesystem`); Netlify/Vercel builds with unusual `HUGO_CACHEDIR`; a cache path that collides with an existing regular file.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/69c853a89ebde244.json. Report an issue: GitHub ↗.