knadh/listmonk · critical

error reading lang file: %s: %v

Error message

error reading lang file: %s: %v

What it means

getI18nLangList reads embedded i18n language JSON files from the stuffbin virtual filesystem. When fs.Get fails to retrieve a listed language file, it wraps the failure with the filename and underlying error. Because language files are embedded at build time, this almost always indicates a broken build/embed rather than runtime user error.

Source

Thrown at cmd/i18n.go:54

		return echo.NewHTTPError(http.StatusBadRequest, "Unknown language.")
	}

	return c.JSON(http.StatusOK, okResp{json.RawMessage(i.JSON())})
}

// getI18nLangList returns the list of available i18n languages.
func getI18nLangList(fs stuffbin.FileSystem) ([]i18nLang, error) {
	list, err := fs.Glob("/i18n/*.json")
	if err != nil {
		return nil, err
	}

	// Read language JSON files from the fs.
	var out []i18nLang
	for _, l := range list {
		b, err := fs.Get(l)
		if err != nil {
			return out, fmt.Errorf("error reading lang file: %s: %v", l, err)
		}

		var r i18nLangRaw
		if err := json.Unmarshal(b.ReadBytes(), &r); err != nil {
			return out, fmt.Errorf("error parsing lang file: %s: %v", l, err)
		}

		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
}

View on GitHub (pinned to 670c01717d)

Solutions

  1. Rebuild the binary using the project's build process (make build) so i18n assets are embedded via stuffbin.
  2. If running from source, use `go run .` which handles asset embedding per the README.
  3. Verify the binary contains the i18n files (stuffbin listing or build logs).
  4. If you added a custom language, ensure it is included in the embedding step.

Example fix

// before
$ go build -o listmonk   # assets not embedded
// after
$ make build             # embeds i18n/static via stuffbin
Defensive patterns

Strategy: try-catch

Validate before calling

// At deploy time: confirm assets are embedded
out, _ := exec.Command("strings", binaryPath).Output()
if !strings.Contains(string(out), "i18n/en.json") {
    log.Fatal("binary missing embedded i18n assets; rebuild with make build")
}

Try / catch

langs, err := getI18nLangList(fs)
if err != nil {
    log.Fatalf("i18n init failed (embedded assets missing?): %v", err)
}

Prevention

When it happens

Trigger: GetServerConfig → getI18nLangList iterates the embedded /i18n/*.json list and fs.Get(l) fails — the file is missing from the binary (built without listmonk's stuffbin packing, e.g. plain `go build` without asset embedding) or the fs mount is misconfigured.

Common situations: Building the binary without the stuffbin embedding step so static/i18n resources are absent; deploying a partially built binary; forks adding a language file to the list without packaging it.

Related errors


AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01). Data as JSON: /api/errors/9b62840d02630747. Report an issue: GitHub.