docker/compose · error
service %q pre_start[%d]: per_replica is not yet supported;
Error message
service %q pre_start[%d]: per_replica is not yet supported; remove per_replica or set it to false
What it means
pre_start hooks currently support only the default per-replica:false mode, where one hook container runs against the first non-running replica's volumes. Setting per_replica: true is rejected up front, before any container I/O, so no partial state is created.
Source
Thrown at pkg/compose/pre_start.go:64
}
}
return pick
}
// runPreStart executes the service's pre_start hooks sequentially, in declared
// order. Each hook runs as an ephemeral container that shares the service
// container's volumes via VolumesFrom and is attached to the same networks.
// A non-zero exit gates service start.
//
// With per_replica: false (the only currently supported mode), the hook sees
// the volumes of the first non-running replica only — anonymous volumes and
// tmpfs mounts are per-replica and not shared. Use named volumes or bind
// mounts for data the hook produces.
func (s *composeService) runPreStart(ctx context.Context, project *types.Project, service types.ServiceConfig, ctr container.Summary, listener api.ContainerEventListener) error {
// Validate every hook up front so an unsupported entry never triggers any I/O.
for i, hook := range service.PreStart {
if hook.PerReplica {
return fmt.Errorf("service %q pre_start[%d]: per_replica is not yet supported; remove per_replica or set it to false", service.Name, i)
}
}
for i, hook := range service.PreStart {
if err := s.runPreStartHook(ctx, project, service, ctr, i, hook, listener); err != nil {
return err
}
}
return nil
}
func (s *composeService) runPreStartHook(
ctx context.Context, project *types.Project, service types.ServiceConfig,
ctr container.Summary, index int, hook types.ServiceHook, listener api.ContainerEventListener,
) error {
created, err := s.createPreStartContainer(ctx, project, service, ctr, hook)
if err != nil {
return err
}View on GitHub (pinned to ddc4b044b6)
Solutions
- Remove per_replica or set it to false in the pre_start entry
- Make the hook idempotent so one shared run suffices (use named volumes or binds, not per-replica anonymous volumes)
- If per-replica init is a hard requirement, run init logic inside each service container (entrypoint wrapper) instead
Example fix
# before
services:
app:
pre_start:
- command: ./init.sh
per_replica: true
# after
services:
app:
pre_start:
- command: ./init.sh
per_replica: false Defensive patterns
Strategy: validation
Validate before calling
for i, h := range service.PreStart {
if h.PerReplica {
return fmt.Errorf("pre_start[%d]: per_replica unsupported on this compose version", i)
}
} Prevention
- Do not use per_replica: true until your compose version documents support
- Design pre_start hooks as single shared runs over named volumes/binds
When it happens
Trigger: A service defines pre_start entries with per_replica: true and docker compose up (or any command materializing the service) runs the runPreStart validation loop.
Common situations: Users copying per-replica init patterns from other orchestrators (e.g. init containers per pod); compose files written against a future/experimental schema; docs from a newer compose where the feature landed.
Related errors
- service %q pre_start[%d] wait error: %s
- service %q pre_start[%d] exited with code %d
- source can not be empty
- destination can not be empty
- invalid filter '${filter}'
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/82b2f753d72c7d28.
Report an issue: GitHub.