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

  1. Validate the file: run it through jq or json.Valid to see the exact syntax error reported in the wrapped message.
  2. Repair the JSON by hand or restore from backup; worst case, delete footer_config.json so GetFooter regenerates a valid default on next call.
  3. If the wrapped error mentions 'cannot unmarshal ... into Go struct field', align the JSON value types with the FooterConfig struct fields (or vice versa).
  4. 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

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


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/3ddb271d180edfca. Report an issue: GitHub.