Billionmail/BillionMail · error
error saving project configuration: %v
Error message
error saving project configuration: %v
What it means
After reading and modifying the config, SetProjectStatus persists it with SaveProjectConfig. If the save fails (write error, serialization error, directory missing/permissions), the error is wrapped as 'error saving project configuration: %v'. The in-memory status change is lost and the on-disk config is unchanged or possibly partially written.
Source
Thrown at core/internal/service/askai/project.go:239
// Return the project status
return config.Status, true, nil
}
// SetProjectStatus updates the status of a project configuration based on the provided domain.
// It reads the existing configuration, modifies the status, and saves the updated configuration back to the file.
func SetProjectStatus(Domain string, status bool) error {
config, err := ReadProjectConfig(Domain)
if err != nil {
return fmt.Errorf("error reading project configuration: %v", err)
}
// Update the project status
config.Status = status
err = SaveProjectConfig(Domain, config)
if err != nil {
return fmt.Errorf("error saving project configuration: %v", err)
}
return nil
}
// ModifyBaseInfo updates the base information of a project configuration based on the provided domain.
// It reads the existing 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 ModifyBaseInfo(Domain string, projectName, description, industry, primaryLogo, secondaryLogo, favicon string, urls []string) error {
config, err := ReadProjectConfig(Domain)
if err != nil {
return fmt.Errorf("error reading project configuration: %v", err)
}
// Update the base information
if projectName != "" {
config.ProjectName = projectName
}
if description != "" {View on GitHub (pinned to fc36c76c05)
Solutions
- Check the process has write permission on PRODUCT_CONFIG_PATH/<domain>/ and the config file
- Confirm the disk has free space and the mount is not read-only
- Ensure the config directory exists (SaveProjectConfig should create it; verify it did)
- Add file locking or serialize writes to avoid concurrent-save corruption
- Inspect the wrapped inner error to pinpoint write vs marshal failure
Example fix
// before
err := askai.SetProjectStatus(domain, true)
// after
if err := askai.SetProjectStatus(domain, true); err != nil {
if strings.Contains(err.Error(), "saving project configuration") {
os.MkdirAll(fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s", domain), 0o755)
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
dir := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s", domain)
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
os.MkdirAll(dir, 0o755)
}
if err := unix.Access(dir, unix.W_OK); err != nil {
return fmt.Errorf("config dir not writable: %w", err)
} Type guard
func configDirWritable(domain string) bool {
probe := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s/.probe", domain)
if err := os.WriteFile(probe, []byte("1"), 0o644); err != nil { return false }
os.Remove(probe)
return true
} Try / catch
err := askai.SetProjectStatus(domain, false)
if err != nil && strings.Contains(err.Error(), "error saving project configuration") {
// check disk space/permissions, then retry
return retryAfterFix(func() error { return askai.SetProjectStatus(domain, false) })
} Prevention
- Check writable volumes and free disk before bulk updates
- Ensure SaveProjectConfig creates its target directory
- Serialize writes with a per-domain mutex
- Use atomic write (temp file + rename) to avoid corruption
- Alert on write failures via the wrapped inner error
When it happens
Trigger: SetProjectStatus(Domain, status) where SaveProjectConfig fails writing PRODUCT_CONFIG_PATH/<domain>/ config: permission denied, directory absent, disk full, or marshal error.
Common situations: Read-only volume in container deployments; config directory deleted between read and save; disk quota exceeded; concurrent writers racing on the same file causing partial writes.
Related errors
- error reading project configuration: %v
- error getting footer config: %v
- project configuration file does not exist: %s
- 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/eacf598046640be0.
Report an issue: GitHub.