{"record":{"id":"c72881bf6419c70a","repo":"docker/compose","slug":"service-q-didn-t-complete-successfully-exit-d","errorCode":null,"errorMessage":"service %q didn't complete successfully: exit %d","messagePattern":"service %q didn't complete successfully: exit (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/compose/convergence.go","lineNumber":248,"sourceCode":"\t\t\t\t\t\tif code == 0 {\n\t\t\t\t\t\t\ts.events.On(containerEvents(waitingFor, exited)...)\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmessageSuffix := fmt.Sprintf(\"%q didn't complete successfully: exit %d\", dep, code)\n\t\t\t\t\t\tif !config.Required {\n\t\t\t\t\t\t\t// optional -> mark as skipped & don't propagate error\n\t\t\t\t\t\t\ts.events.On(containerReasonEvents(waitingFor, skippedEvent,\n\t\t\t\t\t\t\t\tfmt.Sprintf(\"optional dependency %s\", messageSuffix))...)\n\t\t\t\t\t\t\tlogrus.Warnf(\"optional dependency %s\", messageSuffix)\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmsg := fmt.Sprintf(\"service %s\", messageSuffix)\n\t\t\t\t\t\ts.events.On(containerEvents(waitingFor, func(s string) api.Resource {\n\t\t\t\t\t\t\treturn errorEventf(s, \"service %s\", messageSuffix)\n\t\t\t\t\t\t})...)\n\t\t\t\t\t\treturn errors.New(msg)\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tlogrus.Warnf(\"unsupported depends_on condition: %s\", config.Condition)\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\terr := eg.Wait()\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\treturn fmt.Errorf(\"timeout waiting for dependencies\")\n\t}\n\treturn err\n}\n\nfunc shouldWaitForDependency(serviceName string, dependencyConfig types.ServiceDependency, project *types.Project) (bool, error) {\n\tif dependencyConfig.Condition == types.ServiceConditionStarted {\n\t\t// already managed by InDependencyOrder","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/compose/convergence.go#L230-L266","documentation":"During convergence, Compose waits for depends_on dependencies; when a dependency's container exits non-zero while a `service_completed_successfully` condition (or --wait with exit handling) is evaluated, the wait fails with 'service %q didn't complete successfully: exit %d' and the dependent service is never started (unless the dependency is marked optional).","triggerScenarios":"`docker compose up` where a service has depends_on: {condition: service_completed_successfully} and that dependency container exits with a non-zero code (e.g. a migrations one-shot container failing), or `up --wait` on a stack where a dependency exits badly.","commonSituations":"Init/migration containers (flyway migrate, django migrate) failing their command; flaky health-dependent one-shots; a wrong entrypoint or missing env var in the dependency causing exit 1; marking the dependency required when it is optional.","solutions":["Run `docker compose logs <dependency>` to see why it exited non-zero and fix the container itself (missing env var, bad command, missing file)","If failure is acceptable, mark the dependency `required: false` so Compose skips instead of aborting","Re-run the one-shot manually (`docker compose run --rm <dep>`) to iterate on the failure without full up","Verify the image/entrypoint referenced actually exists (exit 127/125 style failures)"],"exampleFix":"# before\nservices:\n  app:\n    depends_on:\n      migrate:\n        condition: service_completed_successfully\n  migrate:\n    command: ./migrate.sh   # exits 1\n# after\nservices:\n  app:\n    depends_on:\n      migrate:\n        condition: service_completed_successfully\n        required: false\n  migrate:\n    command: sh -c \"./migrate.sh || true\"","handlingStrategy":"try-catch","validationCode":"# pre-check the dependency container exits 0 before running dependents\ndocker compose run --rm migrate || echo 'migrate failed — fix before up'","typeGuard":null,"tryCatchPattern":"# in scripts, tolerate a known-failing optional dependency by marking it required: false in the file,\n# and branch on the exit status of `docker compose up --wait`:\nif ! docker compose up --wait; then docker compose logs migrate; exit 1; fi","preventionTips":["Make one-shot dependencies idempotent and loud about their own failures (clear logs, non-zero exit)","Use required: false for dependencies whose failure should not block startup","Smoke-test migration containers standalone in CI before wiring depends_on"],"tags":["depends-on","convergence","startup","healthcheck"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}