{"record":{"id":"2a969027348752c7","repo":"Billionmail/BillionMail","slug":"failed-to-update-docker-compose-yml-v","errorCode":null,"errorMessage":"failed to update docker-compose.yml: %v","messagePattern":"failed to update docker-compose\\.yml: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/multi_ip_domain/config_manager.go","lineNumber":144,"sourceCode":"\treturn nil\n}\n\n// cleanupBackups Clean up backup files\nfunc (m *ConfigManager) cleanupBackups(ctx context.Context, backups map[string]string) {\n\tfor _, backup := range backups {\n\t\tif gfile.Exists(backup) {\n\t\t\tg.Log().Debugf(ctx, \"Cleaning up backup file: %s\", backup)\n\t\t\t_ = os.Remove(backup)\n\t\t}\n\t}\n}\n\n// applyConfigs Apply configurations\nfunc (m *ConfigManager) applyConfigs(ctx context.Context, configs []map[string]interface{}) error {\n\t// 1. Update docker-compose.yml\n\tif err := m.updateDockerCompose(ctx, configs); err != nil {\n\n\t\treturn fmt.Errorf(\"failed to update docker-compose.yml: %v\", err)\n\t}\n\n\t// 2. Update Postfix configurations\n\tif err := m.updatePostfixConfigs(ctx, configs); err != nil {\n\t\treturn fmt.Errorf(\"failed to update Postfix configurations: %v\", err)\n\t}\n\n\treturn nil\n}\n\n// updateDockerCompose Generate docker-compose_addnetwork.yml\nfunc (m *ConfigManager) updateDockerCompose(ctx context.Context, configs []map[string]interface{}) error {\n\toriginalPath := filepath.Join(public.HostWorkDir, \"docker-compose.yml\")\n\toutputPath := filepath.Join(public.HostWorkDir, \"docker-compose_addnetwork.yml\")\n\n\t// 设置临时文件路径\n\t// 容器内路径：/opt/billionmail/core/data (通过 public.AbsPath 获取)\n\t// 宿主机路径：./core-data (相对于 docker-compose.yml 所在目录)","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/multi_ip_domain/config_manager.go#L126-L162","documentation":"applyConfigs is step 1 of ApplyConfigsWithRollback: update the docker-compose topology by generating docker-compose_addnetwork.yml. If updateDockerCompose fails for any reason (dir creation, docker exec, read/modify/write), the error is wrapped with this prefix and triggers rollback of the Postfix configs. It is a wrapper — the root cause is inside updateDockerCompose.","triggerScenarios":"Any updateDockerCompose failure: cannot create the temp data dir, chroot cp of docker-compose.yml fails, temp file empty, content modification error, or copy of the output file back to the host fails.","commonSituations":"Missing /host_root chroot capability or docker API socket inaccessible; docker-compose.yml not at public.HostWorkDir; core-data volume not mounted so the container↔host temp path mapping is broken; malformed compose content.","solutions":["Unwrap the inner error to find the failing step (temp dir, copy, read, modify, or output copy).","Verify docker-compose.yml exists at HostWorkDir and the core-data host volume is mounted and writable.","Confirm the container can run chroot /host_root commands and the Docker API is reachable (docker ps from inside).","After fixing, re-run ApplyConfigsWithRollback; it already restored Postfix configs via rollback, so retry is safe."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// preflight before apply\nif _, err := os.Stat(filepath.Join(public.HostWorkDir, \"docker-compose.yml\")); err != nil {\n\treturn fmt.Errorf(\"docker-compose.yml missing: %v\", err)\n}\nif _, err := os.Stat(filepath.Join(public.HostWorkDir, \"core-data\")); err != nil {\n\treturn fmt.Errorf(\"core-data volume not mounted: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.ApplyConfigsWithRollback(ctx, configs); err != nil {\n\tif strings.Contains(err.Error(), \"failed to update docker-compose.yml\") {\n\t\t// inner cause is in the wrapped text; check docker socket, chroot, mounts\n\t}\n}","preventionTips":["Verify /host_root chroot and Docker API access from the container at startup.","Keep docker-compose.yml at the expected HostWorkDir path.","Ensure the core-data bind mount matches AbsPath('../core/data').","Health-check docker exec capability before config applies."],"tags":["docker-compose","docker","config-apply","wrapper"],"backgroundTag":"docker-compose-update-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}