docker/compose · error
can't watch service %q with action %s without a build contex
Error message
can't watch service %q with action %s without a build context
What it means
While collecting watch rules, compose validates each trigger: a rebuild action requires the service to be built from source, because rebuild re-runs the build. If the service has no build: section (image-only), watch cannot rebuild it and fails naming the service and action.
Source
Thrown at pkg/compose/watch.go:221
)
for serviceName, service := range project.Services {
config, err := loadDevelopmentConfig(service, project)
if err != nil {
return nil, err
}
if service.Develop != nil {
config = service.Develop
}
if config == nil {
continue
}
for _, trigger := range config.Watch {
if trigger.Action == types.WatchActionRebuild {
if service.Build == nil {
return nil, fmt.Errorf("can't watch service %q with action %s without a build context", service.Name, types.WatchActionRebuild)
}
if options.Build == nil {
return nil, fmt.Errorf("--no-build is incompatible with watch action %s in service %s", types.WatchActionRebuild, service.Name)
}
// set the service to always be built - watch triggers `Up()` when it receives a rebuild event
service.PullPolicy = types.PullPolicyBuild
project.Services[serviceName] = service
}
}
for _, trigger := range config.Watch {
if isSync(trigger) && checkIfPathAlreadyBindMounted(trigger.Path, service.Volumes) {
logrus.Warnf("path '%s' also declared by a bind mount volume, this path won't be monitored!\n", trigger.Path)
continue
} else {
shouldInitialSync := trigger.InitialSync
// Check legacy extension attribute for backward compatibilityView on GitHub (pinned to ddc4b044b6)
Solutions
- Remove the rebuild watch trigger from the image-only service, or change its action to sync or sync+restart.
- Add a build: section (context/dockerfile) to the service if rebuild-on-change is intended.
- Split long-lived source watching into a separate build-based compose service.
Example fix
# before
services:
api:
image: registry.example.com/team/api:1.0 # no build:
develop:
watch:
- action: rebuild
path: ./src
# after
services:
api:
image: registry.example.com/team/api:1.0
develop:
watch:
- action: sync
path: ./src
target: /app/src Defensive patterns
Strategy: validation
Validate before calling
func rebuildTriggersBackedByBuild(project *types.Project) error {
for name, svc := range project.Services {
if svc.Develop == nil { continue }
for _, t := range svc.Develop.Watch {
if t.Action == types.WatchActionRebuild && svc.Build == nil {
return fmt.Errorf("service %q has rebuild watch but no build section", name)
}
}
}
return nil
} Try / catch
if _, err := composeService.Watch(ctx, projectName, opts); err != nil {
if strings.Contains(err.Error(), "without a build context") {
// change the trigger action to sync/sync+restart or add build: to the service
}
return err
} Prevention
- Use rebuild actions only on services with a build: section.
- When converting a service to a prebuilt image, prune its develop.watch rebuild rules.
- Lint develop.watch actions against service.build presence in CI.
When it happens
Trigger: Configuring develop.watch with action: rebuild on a service that specifies only image: (no build context). Starting watch then fails during rule construction.
Common situations: Copy-pasting a watch block from a build-based service onto an image-based one; switching a service from build to a prebuilt image but leaving its develop.watch rebuild rule in place.
Related errors
- --wait cannot be combined with --abort-on-container-exit, --
- --detach cannot be combined with --abort-on-container-exit,
- --no-build and --watch are incompatible
- cannot take exclusive lock for project %q: %w
- none of the selected services is configured for watch, see h
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/baee40cf7e6d12f0.
Report an issue: GitHub.