Billionmail/BillionMail · error
error unmarshalling footer config: %v
Error message
error unmarshalling footer config: %v
What it means
After reading footer_config.json, GetFooter unmarshals it into FooterConfig with json.Unmarshal and wraps any decoding failure. This means the file exists and is readable, but its bytes are not valid JSON or do not match FooterConfig's schema (wrong types, e.g. a number where a string is expected). Commonly the file was corrupted by a partial write or edited by hand.
Source
Thrown at core/internal/service/askai/project.go:735
if err != nil {
return FooterConfig{}, fmt.Errorf("error marshalling default footer config: %v", err)
}
err = os.WriteFile(filename, defaultFooterJson, 0644)
if err != nil {
return FooterConfig{}, fmt.Errorf("error saving default footer config file: %v", err)
}
// Return the default footer config if the file does not exist
return defaultFooterConfig, nil
}
data, err := os.ReadFile(filename)
if err != nil {
return FooterConfig{}, fmt.Errorf("error reading footer config file: %v", err)
}
var config FooterConfig
err = json.Unmarshal(data, &config)
if err != nil {
return FooterConfig{}, fmt.Errorf("error unmarshalling footer config: %v", err)
}
return config, nil
}
// ModifyFooter updates the footer configuration for a given domain.
// It reads the existing footer configuration, modifies the specified fields, and saves the updated configuration back to the file.
// If any field is empty, it will not be updated.
func ModifyFooter(Domain string, CopyrightText, Disclaimer string, Text string) error {
config, err := GetFooter(Domain)
if err != nil {
return fmt.Errorf("error getting footer config: %v", err)
}
// Update the footer configuration
if CopyrightText != "" {
config.CopyrightText = CopyrightText
}
if Disclaimer != "" {View on GitHub (pinned to fc36c76c05)
Solutions
- Validate the file: run it through jq or json.Valid to see the exact syntax error reported in the wrapped message.
- Repair the JSON by hand or restore from backup; worst case, delete footer_config.json so GetFooter regenerates a valid default on next call.
- If the wrapped error mentions 'cannot unmarshal ... into Go struct field', align the JSON value types with the FooterConfig struct fields (or vice versa).
- Harden writes (write to temp file + os.Rename) so a crash can never leave a truncated footer_config.json.
Example fix
// before
err = os.WriteFile(filename, data, 0644)
// after
tmp := filename + ".tmp"
if err := os.WriteFile(tmp, data, 0644); err != nil { return err }
if err := os.Rename(tmp, filename); err != nil { return err } // atomic, avoids corrupt partial files Defensive patterns
Strategy: validation
Validate before calling
data, err := os.ReadFile(footerPath)
if err == nil && !json.Valid(data) {
os.Remove(footerPath) // let GetFooter regenerate a valid default
} Type guard
func footerConfigFileValid(path string) bool {
data, err := os.ReadFile(path)
if err != nil { return false }
var c map[string]any
return json.Unmarshal(data, &c) == nil
} Try / catch
if _, err := askai.GetFooter(domain); err != nil {
if strings.Contains(err.Error(), "unmarshalling footer config") {
os.Remove(footerPath) // corrupt: regenerate default, retry once
if cfg, retryErr := askai.GetFooter(domain); retryErr == nil { _ = cfg }
}
return err
} Prevention
- Validate JSON after every manual edit to footer_config.json.
- Use atomic writes (temp + rename) so crashes cannot leave truncated configs.
- Keep FooterConfig field types stable across versions or add migration handling.
- Alert on the corrupt file rather than silently retrying forever.
When it happens
Trigger: Calling GetFooter when footer_config.json contains truncated/corrupt JSON (e.g. an interrupted WriteFile or disk-full during provisioning), hand-edited invalid JSON, or a schema mismatch such as "updateTime": 123 where a string is required.
Common situations: A crash or OOM kill during the initial default-config write left a partial file; an operator edited footer_config.json without validating; an older app version wrote a differently-typed field that the current FooterConfig struct rejects; config copied from another tool with a different format.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- error marshalling default footer config: %v
- error saving default footer config file: %v
- error getting footer config: %v
- error unmarshalling project configuration: %v
- error marshalling project configuration: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/3ddb271d180edfca.
Report an issue: GitHub.