gohugoio/hugo · error

error copying static files

Error message

error copying static files: %w

What it means

During `fullBuild`, Hugo runs `c.copyStatic()` concurrently with site building. This error wraps any failure from copying the project's `static/` directory (and theme static dirs) into the publish directory. It surfaces I/O, symlink, or filesystem-layer problems rather than template/content problems.

Solutions

  1. Inspect the wrapped underlying error to locate the offending path.
  2. Check permissions and resolve any broken symlinks under `static/` and theme static dirs.
  3. Confirm the configured `publishDir` is writable and has free space.
  4. Validate custom filesystem mounts in `hugo.toml` (the `[[mounts]]` blocks) point at real directories.

Example fix

// before
// static/img -> ../../missing   (broken symlink)
// after
// rm static/img && cp -r ../real/imgs static/img
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: walk the static dir and verify every file is readable;
// check the publishDir is writable.
func validateStatic(staticDir, publishDir string) error {
  return filepath.Walk(staticDir, func(p string, fi os.FileInfo, err error) error {
    if err != nil { return err }
    if fi.IsDir() { return nil }
    f, e := os.Open(p); if e != nil { return e }
    return f.Close()
  })
}

Type guard

null

Try / catch

// On copyStatic failure, surface the offending path from the wrapped error.
var pathErr *os.PathError
if errors.As(err, &pathErr) {
  log.Printf("static copy failed at %s: %v", pathErr.Path, pathErr)
}

Prevention

When it happens

Trigger: Fires when `copyStatic` returns non-nil — e.g. a static file is unreadable, a symlink loop exists, the destination is on a read-only filesystem, or a custom Hugo filesystem mount is misconfigured.

Common situations: A broken symlink or permission-restricted file under `static/`; a `publishDir` set to a read-only or out-of-space location; misconfigured module/theme static mounts pointing at non-existent paths; running out of inode/disk space during copy.

Related errors


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

Appendix: source

Thrown at commands/hugobuilder.go:577

func (c *hugoBuilder) fullBuild(noBuildLock bool) error {
	var (
		g         errgroup.Group
		langCount map[string]uint64
	)

	c.r.logger.Println("Start building sites … ")
	c.r.logger.Println(hugo.BuildVersionString())
	c.r.logger.Println()
	if terminal.IsTerminal(os.Stdout) {
		defer func() {
			fmt.Print(showCursor + clearLine)
		}()
	}

	copyStaticFunc := func() error {
		cnt, err := c.copyStatic()
		if err != nil {
			return fmt.Errorf("error copying static files: %w", err)
		}
		langCount = cnt
		return nil
	}
	buildSitesFunc := func() error {
		if err := c.buildSites(noBuildLock); err != nil {
			return fmt.Errorf("error building site: %w", err)
		}
		return nil
	}
	// Do not copy static files and build sites in parallel if cleanDestinationDir is enabled.
	// This flag deletes all static resources in /public folder that are missing in /static,
	// and it does so at the end of copyStatic() call.
	var cleanDestinationDir bool
	c.withConf(func(conf *commonConfig) {
		cleanDestinationDir = conf.configs.Base.CleanDestinationDir
	})
	if cleanDestinationDir {

View on GitHub (pinned to 52c9bd7908)