{"record":{"id":"d10e19e52503e8fb","repo":"Billionmail/BillionMail","slug":"failed-to-apply-configurations-v-rollback-also","errorCode":null,"errorMessage":"failed to apply configurations: %v, rollback also failed: %v","messagePattern":"failed to apply configurations: (.+?), rollback also failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"core/internal/service/multi_ip_domain/config_manager.go","lineNumber":70,"sourceCode":"}\n\n// ApplyConfigsWithRollback Apply configurations and rollback on failure\nfunc (m *ConfigManager) ApplyConfigsWithRollback(ctx context.Context, configs []map[string]interface{}) error {\n\n\tm.fileLocker.Lock()\n\tdefer m.fileLocker.Unlock()\n\n\tbackups, err := m.createBackups(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create backup: %v\", err)\n\t}\n\n\t// Apply configurations\n\tif err := m.applyConfigs(ctx, configs); err != nil {\n\n\t\tg.Log().Debugf(ctx, \"Failed to apply configurations, rolling back... Error: %v\", err)\n\t\tif rollbackErr := m.rollback(ctx, backups); rollbackErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to apply configurations: %v, rollback also failed: %v\", err, rollbackErr)\n\t\t}\n\t\treturn fmt.Errorf(\"failed to apply configurations, but rollback succeeded: %v\", err)\n\t}\n\n\tm.cleanupBackups(ctx, backups)\n\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 {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/multi_ip_domain/config_manager.go#L52-L88","documentation":"ApplyConfigsWithRollback failed to apply the new multi-IP domain configurations AND the rollback of the earlier backups also failed. This is the worst-case outcome: the system is left in a partially modified, unknown config state with no automatic restoration, so the caller gets both errors combined.","triggerScenarios":"m.applyConfigs(ctx, configs) returned an error (write failure, invalid config) and the subsequent m.rollback(ctx, backups) also errored — e.g. backup files were deleted between backup and rollback, or write permissions changed mid-operation.","commonSituations":"Disk filled up during apply so rollback writes also fail; another process deleted/moved the .backup.* files; config directory became read-only; concurrent ApplyConfigsWithRollback runs interfering despite locking scope.","solutions":["Manually inspect postfix main.cf/master.cf and restore from the remaining .backup.* files under the config directory","Investigate why both apply and rollback failed (usually disk/permissions) via mail server and app logs","Fix the root cause, then re-run ApplyConfigsWithRollback to converge to a known state","Consider verifying backup files exist (or copying them to a temp dir) immediately before rollback"],"exampleFix":"// before\nif rollbackErr := m.rollback(ctx, backups); rollbackErr != nil {\n    return fmt.Errorf(\"failed to apply configurations: %v, rollback also failed: %v\", err, rollbackErr)\n}\n// after\nif rollbackErr := m.rollback(ctx, backups); rollbackErr != nil {\n    g.Log().Errorf(ctx, \"MANUAL INTERVENTION REQUIRED: apply err=%v rollback err=%v backups=%v\", err, rollbackErr, backups)\n    return fmt.Errorf(\"failed to apply configurations: %v, rollback also failed: %v\", err, rollbackErr)\n}","handlingStrategy":"fallback","validationCode":"// No caller-side check can fully prevent dual failure; pre-flight the environment:\nif !writable(PostfixMainCfPath) || !writable(PostfixMasterCfPath) {\n    return errors.New(\"postfix configs not writable; apply would fail without rollback safety\")\n}","typeGuard":null,"tryCatchPattern":"err := manager.ApplyConfigsWithRollback(ctx, configs)\nif err != nil && strings.Contains(err.Error(), \"rollback also failed\") {\n    // CRITICAL: unknown state — page ops, restore manually from .backup.* files\n    pageOnCall(err)\n    restoreFromLatestBackups(PostfixMainCfPath, PostfixMasterCfPath)\n}","preventionTips":["Copy backups to a secondary location (temp dir) so rollback survives config-dir failures","Pre-check disk space and permissions before applying","Serialize apply operations across processes to avoid interference","Alert loudly (critical) on this error — manual intervention is required"],"tags":["configuration","rollback","postfix","state-corruption"],"backgroundTag":"rollback-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"}