Billionmail/BillionMail · error

error marshalling footer config: %v

Error message

error marshalling footer config: %v

What it means

ModifyFooter in core/internal/service/askai/project.go:764 fails when json.Marshal cannot serialize the updated FooterConfig struct before it is written to PRODUCT_CONFIG_PATH/<domain>/footer_config.json. Marshal errors are rare for plain config structs and almost always indicate an unsupported value (channel, func, cyclic pointer) embedded in the struct. The wrapped json.MarshalTypeError is returned so the caller can surface why serialization failed.

Source

Thrown at core/internal/service/askai/project.go:764

		return fmt.Errorf("error getting footer config: %v", err)
	}

	// Update the footer configuration
	if CopyrightText != "" {
		config.CopyrightText = CopyrightText
	}
	if Disclaimer != "" {
		config.Disclaimer = Disclaimer
	}
	if Text != "" {
		config.Text = Text
	}

	config.UpdateTime = public.GetNowTime()
	filename := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s/footer_config.json", Domain)
	data, err := json.Marshal(config)
	if err != nil {
		return fmt.Errorf("error marshalling footer config: %v", err)
	}
	err = os.WriteFile(filename, data, 0644)
	if err != nil {
		return fmt.Errorf("error saving footer config file: %v", err)
	}
	return nil
}

// GetPrompt retrieves the prompt configuration for a given domain from a JSON file.
// It reads the prompt configuration file and returns a PromptConfig struct.
// If the file does not exist or cannot be read, it returns an error.
func GetPrompt(Domain string) (PromptConfig, error) {
	filename := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s/prompt_config.json", Domain)
	if !public.FileExists(filename) {
		// If the prompt config file does not exist, return a default prompt config
		// This allows the system to handle cases where the prompt configuration has not been set up
		// and avoids errors when trying to read a non-existent file.
		// It also allows the user to create a new prompt configuration without needing to handle file

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Inspect the wrapped error (%v) for the json.MarshalTypeError field/type to identify the offending FooterConfig field.
  2. Remove or make serializable any func/chan/complex fields added to FooterConfig; encode them as strings or IDs.
  3. Check custom MarshalJSON implementations on FooterConfig and its field types for error paths.
  4. If a cycle is suspected, add pointer guards or store plain values instead of shared pointers.

Example fix

// before
type FooterConfig struct {
    Text string
    OnSave func() // unsupported by json.Marshal
}
// after
type FooterConfig struct {
    Text string
    OnSaveName string `json:"onSaveName"` // serializable representation
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: validate serializability before calling ModifyFooter
func footerConfigSerializable(domain string) error {
    cfg, err := GetFooter(domain)
    if err != nil {
        return err
    }
    _, err = json.Marshal(cfg)
    return err
}

Type guard

func isMarshalable(v any) bool {
    _, err := json.Marshal(v)
    return err == nil
}

Try / catch

if err := askai.ModifyFooter(domain, copyright, disclaimer, text); err != nil {
    var mte *json.MarshalTypeError
    if errors.As(err, &mte) {
        log.Printf("footer config field %s (%s) not serializable", mte.Field, mte.Type)
    } else {
        log.Printf("modify footer failed: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling ModifyFooter(domain, copyrightText, disclaimer, text) when the loaded FooterConfig (from GetFooter) contains a field json.Marshal cannot encode: an unsupported type (func, chan, complex), a custom MarshalJSON method that returns an error, or a cyclic pointer/graph (unsupported recursively).

Common situations: A developer extends FooterConfig with a non-serializable field (e.g., a callback or time.Time with a broken custom marshaler), or a custom MarshalJSON on FooterConfig/fields returns an error on the current data, or a data race corrupts pointer fields into a cycle between GetFooter and Marshal.

Related errors


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