Billionmail/BillionMail · error
error saving images file: %v
Error message
error saving images file: %v
What it means
SaveImagesConfig wraps any failure of os.WriteFile when persisting the domain's images.json (under PRODUCT_CONFIG_PATH/<Domain>/). The library throws it whenever the file cannot be marshalled-then-written, typically due to filesystem/permission problems, and it surfaces the underlying OS error via %v.
Source
Thrown at core/internal/service/askai/project.go:900
HeadingFont string `json:"heading_font"`
LinkFooterColor string `json:"link_footer_color"`
LinkSocialColor string `json:"link_social_color"`
PageBackground string `json:"page_background"`
TextColor string `json:"text_color"`
}
func SaveImagesConfig(Domain string, images []ImageInfo) error {
imagesPath := fmt.Sprintf("%s/%s/images.json", PRODUCT_CONFIG_PATH, Domain)
if !public.FileExists(PRODUCT_CONFIG_PATH + "/" + Domain) {
os.MkdirAll(PRODUCT_CONFIG_PATH+"/"+Domain, os.ModePerm)
}
data, err := json.MarshalIndent(images, "", " ")
if err != nil {
return fmt.Errorf("error marshalling images: %v", err)
}
err = os.WriteFile(imagesPath, data, 0644)
if err != nil {
return fmt.Errorf("error saving images file: %v", err)
}
return nil
}
func ReadImagesConfig(Domain string) ([]ImageInfo, error) {
imagesPath := fmt.Sprintf("%s/%s/images.json", PRODUCT_CONFIG_PATH, Domain)
if !public.FileExists(imagesPath) {
os.WriteFile(imagesPath, []byte("[]"), 0644)
}
data, err := os.ReadFile(imagesPath)
if err != nil {
return []ImageInfo{}, fmt.Errorf("error reading images configuration file: %v", err)
}
var images []ImageInfo
err = json.Unmarshal(data, &images)
if err != nil {
return []ImageInfo{}, fmt.Errorf("error unmarshalling images configuration: %v", err)View on GitHub (pinned to fc36c76c05)
Solutions
- Ensure the target directory exists before writing: os.MkdirAll(fmt.Sprintf("%s/%s", PRODUCT_CONFIG_PATH, Domain), 0755) at the top of SaveImagesConfig.
- Check permissions/ownership of PRODUCT_CONFIG_PATH and images.json (chown/chmod to the service user).
- Verify the volume is writable and not full (df -h, mount flags).
- Log the full path from the wrapped error to confirm PRODUCT_CONFIG_PATH points where you expect.
Example fix
// before
func SaveImagesConfig(Domain string, images []ImageInfo) error {
data, err := json.MarshalIndent(images, "", " ")
if err != nil {
return fmt.Errorf("error marshalling images: %v", err)
}
err = os.WriteFile(imagesPath, data, 0644)
if err != nil {
return fmt.Errorf("error saving images file: %v", err)
}
// after
func SaveImagesConfig(Domain string, images []ImageInfo) error {
if err := os.MkdirAll(filepath.Join(PRODUCT_CONFIG_PATH, Domain), 0755); err != nil {
return fmt.Errorf("error creating images dir: %v", err)
}
data, err := json.MarshalIndent(images, "", " ")
if err != nil {
return fmt.Errorf("error marshalling images: %v", err)
}
tmp := imagesPath + ".tmp"
if err := os.WriteFile(tmp, data, 0644); err != nil {
return fmt.Errorf("error saving images file: %v", err)
}
return os.Rename(tmp, imagesPath)
} Defensive patterns
Strategy: validation
Validate before calling
dir := filepath.Join(PRODUCT_CONFIG_PATH, Domain)
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
return fmt.Errorf("images dir %s missing", dir)
}
if f, err := os.OpenFile(filepath.Join(dir, "images.json"), os.O_WRONLY|os.O_CREATE, 0644); err != nil {
return fmt.Errorf("images.json not writable: %v", err)
} else {
f.Close()
} Type guard
func canWrite(path string) bool {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return false
}
_ = f.Close()
return true
} Try / catch
if err := SaveImagesConfig(domain, images); err != nil {
if strings.Contains(err.Error(), "error saving images file") {
// handle write failure: check disk/permissions, retry or queue
}
} Prevention
- Always MkdirAll the target directory before first write
- Run the service with a dedicated user owning PRODUCT_CONFIG_PATH
- Monitor disk space and mount flags on config volumes
- Use atomic temp-file + rename writes
When it happens
Trigger: Calling SaveImagesConfig (directly or via UploadImage/ModifyImage/RemoveImage flows) when the PRODUCT_CONFIG_PATH/<Domain> directory does not exist, the process lacks write permission on images.json, or the disk is full.
Common situations: Deployments where the config directory was never created before first save; running the service as a non-root user after files were created by root; read-only container filesystems; full disk on the host.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- error reading images configuration file: %v
- error saving images configuration: %v
- error reading project configuration file: %v
- error writing project configuration file: %v
- error writing knowledge base file: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/36afb7c6dbcddffa.
Report an issue: GitHub.