knadh/listmonk · critical
error reading default i18n language file: %s: %v
Error message
error reading default i18n language file: %s: %v
What it means
getI18nLang initializes the i18n system by first reading the default English pack (/i18n/en.json) from the stuffbin filesystem, since other languages fall back to it. If that read fails it wraps the error with the 'en' code. A missing default pack breaks i18n initialization, though per the surrounding comment the app may log a warning instead of halting.
Source
Thrown at cmd/i18n.go:80
out = append(out, i18nLang(r))
}
// Sort by language code.
sort.SliceStable(out, func(i, j int) bool {
return out[i].Code < out[j].Code
})
return out, nil
}
// The bool indicates whether the specified language could be loaded. If it couldn't
// be, the app shouldn't halt but throw a warning.
func getI18nLang(lang string, fs stuffbin.FileSystem) (*i18n.I18n, bool, error) {
const def = "en"
b, err := fs.Read(fmt.Sprintf("/i18n/%s.json", def))
if err != nil {
return nil, false, fmt.Errorf("error reading default i18n language file: %s: %v", def, err)
}
// Initialize with the default language.
i, err := i18n.New(b)
if err != nil {
return nil, false, fmt.Errorf("error unmarshalling i18n language: %s: %v", lang, err)
}
// Load the selected language on top of it.
b, err = fs.Read(fmt.Sprintf("/i18n/%s.json", lang))
if err != nil {
return i, true, fmt.Errorf("error reading i18n language file: %s: %v", lang, err)
}
if err := i.Load(b); err != nil {
return i, true, fmt.Errorf("error loading i18n language file: %s: %v", lang, err)
}
return i, true, nilView on GitHub (pinned to 670c01717d)
Solutions
- Rebuild with the standard build pipeline (make build) so /i18n/en.json is embedded via stuffbin.
- Ensure i18n/en.json exists in the repo and is included in the packaging list.
- If running from source, use `go run .` per the README so assets are packed automatically.
- Keep 'en' present even when localizing — it is the required fallback default.
Example fix
// before $ rm i18n/en.json && make build // after $ git checkout -- i18n/en.json && make build
Defensive patterns
Strategy: try-catch
Validate before calling
b, err := fs.Read("/i18n/en.json")
if err != nil {
log.Fatal("default language pack missing; rebuild binary with embedded assets")
} Try / catch
i, warn, err := getI18nLang(lang, fs)
if err != nil {
log.Printf("i18n unavailable, continuing without translations: %v", err)
return nil, warn, nil // app continues, per library's non-fatal policy
} Prevention
- Never delete or rename i18n/en.json — it is the mandatory fallback.
- Build with make build to embed the default pack.
- Include /i18n/en.json in any asset-trimming allowlist.
- Add a startup health check that reads en.json from the embedded FS.
When it happens
Trigger: initI18n or GetI18nLang → getI18nLang calls fs.Read("/i18n/en.json") and the file is absent from the embedded filesystem — typically a binary built without stuffbin asset embedding, or a renamed/removed en.json in a fork.
Common situations: Deploying a bare `go build` binary without embedded assets; trimming i18n files and accidentally deleting en.json; renaming language files without keeping 'en' as the default.
Related errors
- error reading lang file: %s: %v
- error parsing lang file: %s: %v
- 'email' column not found
- subscribers.invalidEmail
- token was not found or has expired
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/b00b6d38cab7c445.
Report an issue: GitHub.