gohugoio/hugo · error
failed to open translations file %q:: %w
Error message
failed to open translations file %q:: %w
What it means
Raised in addTranslationFile (langs/i18n/translationProvider.go:110) when opening an i18n translation file from the mounted filesystem fails before parsing. Hugo walks all files in the i18n component (project, themes, modules) and opens each to feed go-i18n's bundle; an Open error here is an I/O problem — the file exists in the directory listing but can't be read. (The doubled "::" in the message is a long-standing quirk of the format string.)
Source
Thrown at langs/i18n/translationProvider.go:110
for _, info := range files {
if err := addTranslationFile(bundle, source.NewFileInfo(info)); err != nil {
return err
}
}
tp.t = NewTranslator(bundle, dst.Conf, dst.Log)
dst.Translate = tp.getTranslateFunc(dst)
return nil
}
const artificialLangTagPrefix = "art-x-"
func addTranslationFile(bundle *i18n.Bundle, r *source.File) error {
f, err := r.FileInfo().Meta().Open()
if err != nil {
return fmt.Errorf("failed to open translations file %q:: %w", r.LogicalName(), err)
}
b := helpers.ReaderToBytes(f)
f.Close()
name := r.LogicalName()
lang := paths.Filename(name)
tag := language.Make(lang)
if tag == language.Und {
try := artificialLangTagPrefix + lang
_, err = language.Parse(try)
if err != nil {
return fmt.Errorf("%q: %s", try, err)
}
name = artificialLangTagPrefix + name
}
_, err = bundle.ParseMessageFileBytes(b, name)View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Check the named file exists and is readable: `ls -l i18n/` in the project and in any theme/module providing it.
- Fix broken symlinks or restore the missing target file.
- Correct permissions (e.g. `chmod a+r i18n/*.yaml`), especially in container builds.
- If the file comes from a module, re-vendor or re-fetch (`hugo mod vendor` / `hugo mod get -u`).
Example fix
# before: i18n/en.yaml is a broken symlink $ ls -l i18n/en.yaml lrwxrwxrwx en.yaml -> ../shared/en.yaml (missing) # after: replace with the real file $ cp ../shared-i18n/en.yaml i18n/en.yaml
Defensive patterns
Strategy: validation
Validate before calling
// Verify i18n files exist and are readable before build
entries, err := os.ReadDir("i18n")
if err == nil {
for _, e := range entries {
f, err := os.Open(filepath.Join("i18n", e.Name()))
if err != nil { return fmt.Errorf("unreadable translation file %s: %w", e.Name(), err) }
f.Close()
}
} Try / catch
if err != nil && strings.Contains(err.Error(), "failed to open translations file") {
return fmt.Errorf("check the named i18n file exists, is readable, and isn't a broken symlink: %w", err)
} Prevention
- Keep i18n files named by language code with a supported extension (en.toml, fr.yaml, de.json)
- Check file permissions on i18n/ files, especially after CI checkouts or Docker COPY
- Avoid broken symlinks in i18n directories (symlinks may also be restricted by Hugo's security model)
- Validate i18n files parse by running a local `hugo` build before pushing
When it happens
Trigger: An i18n/*.{yaml,toml,json} file that is unreadable at open time: permission denied, a broken symlink inside i18n/, a file removed between walk and open, or a module mount pointing at a path that fails on read.
Common situations: Broken symlinks in themes or vendored modules, restrictive file permissions after copying files as root (e.g. in Docker builds), or network/overlay filesystems dropping files mid-build.
Related errors
- failed to load translations: %w%s
- language %q not found
- 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/a3e61b6c5c1053af.json.
Report an issue: GitHub ↗.