{"record":{"id":"f037ce87e2d1ef61","repo":"Billionmail/BillionMail","slug":"failed-to-create-backup-for-s-v","errorCode":null,"errorMessage":"failed to create backup for %s: %v","messagePattern":"failed to create backup for (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/multi_ip_domain/config_manager.go","lineNumber":94,"sourceCode":"\treturn nil\n}\n\n// createBackups Create backups for Postfix's main.cf and master.cf\nfunc (m *ConfigManager) createBackups(ctx context.Context) (map[string]string, error) {\n\tbackups := make(map[string]string)\n\n\tfiles := []string{PostfixMainCfPath, PostfixMasterCfPath}\n\n\tfor _, file := range files {\n\t\tif gfile.Exists(file) {\n\t\t\tcontent, err := ioutil.ReadFile(file)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to read file %s: %v\", file, err)\n\t\t\t}\n\n\t\t\tbackupPath := fmt.Sprintf(\"%s.backup.%d\", file, time.Now().UnixNano())\n\t\t\tif err := ioutil.WriteFile(backupPath, content, 0644); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to create backup for %s: %v\", file, err)\n\t\t\t}\n\t\t\tg.Log().Debugf(ctx, \"Created backup for %s at %s\", file, backupPath)\n\t\t\tbackups[file] = backupPath\n\t\t}\n\t}\n\n\treturn backups, nil\n}\n\n// rollback Roll back configurations\nfunc (m *ConfigManager) rollback(ctx context.Context, backups map[string]string) error {\n\tvar allErrors []string\n\tfor file, backup := range backups {\n\t\tif gfile.Exists(backup) {\n\t\t\tg.Log().Infof(ctx, \"Rolling back %s from %s\", file, backup)\n\t\t\tcontent, err := ioutil.ReadFile(backup)\n\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"failed to read backup file %s: %v\", backup, err)","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/multi_ip_domain/config_manager.go#L76-L112","documentation":"createBackups snapshots Postfix main.cf and master.cf before ApplyConfigsWithRollback modifies them. When ioutil.WriteFile cannot write the timestamped backup file (<path>.backup.<UnixNano>), the whole apply operation aborts before any change is made. This means the backup directory is not writable or the filesystem is broken.","triggerScenarios":"ioutil.WriteFile fails writing '<main.cf|master.cf>.backup.<unixnano>': read-only filesystem, missing write permission on conf/postfix dir, disk full, or the path is a directory.","commonSituations":"Container running with a read-only mount over ../conf/postfix; running as non-root user without ownership of the postfix conf dir; disk quota exhausted; SELinux/AppArmor denial.","solutions":["Check the wrapped %v OS error and fix filesystem permissions: chown/chmod the core/conf/postfix directory so the process user can write.","Verify the volume is not mounted read-only (docker inspect the mount's RW flag); remount as writable.","Free disk space or raise the quota on the filesystem holding the conf directory.","If SELinux is enforcing, relabel with restorecon or adjust the container's SELinux policy."],"exampleFix":"// before\nif err := ioutil.WriteFile(backupPath, content, 0644); err != nil {\n\treturn nil, fmt.Errorf(\"failed to create backup for %s: %v\", file, err)\n}\n// after\nif err := os.MkdirAll(filepath.Dir(backupPath), 0o755); err != nil {\n\treturn nil, fmt.Errorf(\"backup dir unavailable: %v\", err)\n}\nif err := ioutil.WriteFile(backupPath, content, 0o600); err != nil {\n\treturn nil, fmt.Errorf(\"failed to create backup for %s (check dir permissions/disk space): %v\", file, err)\n}","handlingStrategy":"validation","validationCode":"// before calling ApplyConfigsWithRollback\nfor _, f := range []string{multi_ip_domain.PostfixMainCfPath, multi_ip_domain.PostfixMasterCfPath} {\n\tif fi, err := os.Stat(f); err == nil {\n\t\tif err := syscall.Access(f, os.O_WRONLY); err != nil {\n\t\t\treturn fmt.Errorf(\"no write access to %s (or its dir): %v\", f, err)\n\t\t}\n\t\t_ = fi\n\t}\n}\nout, _ := exec.Command(\"df\", \"-h\", filepath.Dir(multi_ip_domain.PostfixMainCfPath)).Output() // ensure free space","typeGuard":null,"tryCatchPattern":"if err := mgr.ApplyConfigsWithRollback(ctx, configs); err != nil {\n\tif strings.Contains(err.Error(), \"failed to create backup\") {\n\t\t// fix permissions/disk before retry; nothing was modified yet\n\t}\n}","preventionTips":["Ensure the process user owns conf/postfix and its parent directory.","Mount conf volumes rw, never ro.","Monitor free disk space on the conf volume.","Run in a container as a non-root user with explicit chown at startup."],"tags":["filesystem","permissions","backup","go"],"backgroundTag":"backup-write-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}