docker/compose · error

service %q didn't complete successfully: exit %d

Error message

service %q didn't complete successfully: exit %d

What it means

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).

Source

Thrown at pkg/compose/convergence.go:248

						if code == 0 {
							s.events.On(containerEvents(waitingFor, exited)...)
							return nil
						}

						messageSuffix := fmt.Sprintf("%q didn't complete successfully: exit %d", dep, code)
						if !config.Required {
							// optional -> mark as skipped & don't propagate error
							s.events.On(containerReasonEvents(waitingFor, skippedEvent,
								fmt.Sprintf("optional dependency %s", messageSuffix))...)
							logrus.Warnf("optional dependency %s", messageSuffix)
							return nil
						}

						msg := fmt.Sprintf("service %s", messageSuffix)
						s.events.On(containerEvents(waitingFor, func(s string) api.Resource {
							return errorEventf(s, "service %s", messageSuffix)
						})...)
						return errors.New(msg)
					}
				default:
					logrus.Warnf("unsupported depends_on condition: %s", config.Condition)
					return nil
				}
			}
		})
	}
	err := eg.Wait()
	if errors.Is(err, context.DeadlineExceeded) {
		return fmt.Errorf("timeout waiting for dependencies")
	}
	return err
}

func shouldWaitForDependency(serviceName string, dependencyConfig types.ServiceDependency, project *types.Project) (bool, error) {
	if dependencyConfig.Condition == types.ServiceConditionStarted {
		// already managed by InDependencyOrder

View on GitHub (pinned to ddc4b044b6)

Solutions

  1. Run `docker compose logs <dependency>` to see why it exited non-zero and fix the container itself (missing env var, bad command, missing file)
  2. If failure is acceptable, mark the dependency `required: false` so Compose skips instead of aborting
  3. Re-run the one-shot manually (`docker compose run --rm <dep>`) to iterate on the failure without full up
  4. Verify the image/entrypoint referenced actually exists (exit 127/125 style failures)

Example fix

# before
services:
  app:
    depends_on:
      migrate:
        condition: service_completed_successfully
  migrate:
    command: ./migrate.sh   # exits 1
# after
services:
  app:
    depends_on:
      migrate:
        condition: service_completed_successfully
        required: false
  migrate:
    command: sh -c "./migrate.sh || true"
Defensive patterns

Strategy: try-catch

Validate before calling

# pre-check the dependency container exits 0 before running dependents
docker compose run --rm migrate || echo 'migrate failed — fix before up'

Try / catch

# in scripts, tolerate a known-failing optional dependency by marking it required: false in the file,
# and branch on the exit status of `docker compose up --wait`:
if ! docker compose up --wait; then docker compose logs migrate; exit 1; fi

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15). Data as JSON: /api/errors/c72881bf6419c70a. Report an issue: GitHub.