gohugoio/hugo · error
failed to copy to %q: %w
Error message
failed to copy to %q: %w
What it means
Thrown when copying a non-resource output file (e.g. one emitted via the copy/file loader) to the publish directory fails. Either helpers.OpenFilesForWriting or io.Copy returned an error, and the printed targetFilenames show where the write failed.
Source
Thrown at internal/js/esbuild/batch.go:716
targetFilenames = append(targetFilenames, targetFilename)
}
fs := b.client.d.BaseFs.PublishFs
if err := func() error {
fw, err := helpers.OpenFilesForWriting(fs, targetFilenames...)
if err != nil {
return err
}
defer fw.Close()
fr := bytes.NewReader(o.Contents)
_, err = io.Copy(fw, fr)
return err
}(); err != nil {
return nil, fmt.Errorf("failed to copy to %q: %w", targetFilenames, err)
}
}
}
p := &Package{
id: path.Join(NsBatch, b.id),
b: b,
groups: groups,
}
return p, nil
}
func (b *batcher) removeNotSet() bool {
// We already have the lock.
var removed bool
currentBuildID := b.buildCount
for k, v := range b.scriptGroups {View on GitHub (pinned to 52c9bd7908)
Solutions
- Check write permissions on the publish directory (often public/).
- Free disk space on the volume holding the publish dir.
- Inspect the target path printed for invalid characters or traversal; verify each multihost base path is correct.
- On Windows, exclude the Hugo publish dir from anti-virus scanning.
Defensive patterns
Strategy: try-catch
Validate before calling
// Before the build, write and remove a sentinel file in the publish dir to
// confirm the process has write access.
sentinel := filepath.Join(publishDir, ".hugo-write-probe")
if err := os.WriteFile(sentinel, []byte("x"), 0o644); err != nil {
return fmt.Errorf("publish dir not writable: %w", err)
}
_ = os.Remove(sentinel) Try / catch
On copy failure, inspect the wrapped error for syscall.EACCES or ENOSPC and surface a targeted message (permissions vs. disk-full) instead of the generic copy error.
Prevention
- Run Hugo as a user with write access to public/.
- Clean the publish dir between builds in CI to avoid stale-file locks.
- On Windows, exclude the Hugo publish dir from anti-virus scanning.
When it happens
Trigger: Esbuild emits an output file that isn't recognized as a resource (no media type or not in a path group), so Hugo copies it directly to each multihost-aware target. The copy fails because the publish directory is not writable, is out of space, or the joined target path is invalid.
Common situations: publishDir (often public/) is read-only or owned by another user; CI runs Hugo as a non-privileged user; out of disk; misconfigured multihost producing invalid joined paths; on Windows an anti-virus locks the destination file.
Related errors
- failed to save file %q: %s
- walk: Readdir: %w
- fileInfo: %w
- data: failed to open %q: %w
- failed to read import %q: %w
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/35302cf15f2b5a08.
Report an issue: GitHub.