{"record":{"id":"62ba9108c06f6e09","repo":"docker/compose","slug":"interactive-run-is-not-supported-in-dry-run-mode","errorCode":null,"errorMessage":"interactive run is not supported in dry-run mode","messagePattern":"interactive run is not supported in dry-run mode","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/dryrun/dryrunclient.go","lineNumber":93,"sourceCode":"\t}\n\treturn &DryRunClient{\n\t\tapiClient:  apiClient,\n\t\tcontainers: []containerType.Summary{},\n\t\texecs:      sync.Map{},\n\t\tresolver:   imagetools.New(configFile),\n\t}, nil\n}\n\nfunc getCallingFunction() string {\n\tpc, _, _, _ := runtime.Caller(2)\n\tfullName := runtime.FuncForPC(pc).Name()\n\treturn fullName[strings.LastIndex(fullName, \".\")+1:]\n}\n\n// All methods and functions which need to be overridden for dry run.\n\nfunc (d *DryRunClient) ContainerAttach(ctx context.Context, container string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) {\n\treturn client.ContainerAttachResult{}, errors.New(\"interactive run is not supported in dry-run mode\")\n}\n\nfunc (d *DryRunClient) ContainerCreate(ctx context.Context, options client.ContainerCreateOptions) (client.ContainerCreateResult, error) {\n\td.containers = append(d.containers, containerType.Summary{\n\t\tID:     options.Name,\n\t\tNames:  []string{options.Name},\n\t\tLabels: options.Config.Labels,\n\t\tHostConfig: struct {\n\t\t\tNetworkMode string            `json:\",omitempty\"`\n\t\t\tAnnotations map[string]string `json:\",omitempty\"`\n\t\t}{},\n\t})\n\treturn client.ContainerCreateResult{ID: options.Name}, nil\n}\n\nfunc (d *DryRunClient) ContainerInspect(ctx context.Context, container string, options client.ContainerInspectOptions) (client.ContainerInspectResult, error) {\n\tcontainerJSON, err := d.apiClient.ContainerInspect(ctx, container, options)\n\tif err != nil {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/dryrun/dryrunclient.go#L75-L111","documentation":"In --dry-run mode Compose swaps the Docker client for DryRunClient, which simulates mutations but cannot simulate an interactive TTY attach. Any code path that would attach the terminal to a container (ContainerAttach, used by run -it / up with interactive allocation) is hard-blocked so dry-run output stays pure and deterministic.","triggerScenarios":"`docker compose run --dry-run -it <svc>` or any API path that calls ContainerAttach while the dry-run client is active.","commonSituations":"CI or scripted dry-run validation of commands that were copied from interactive usage; testing `docker compose run` pipelines that still carry -it flags.","solutions":["Drop the interactive flags for the dry-run invocation: `docker compose run --dry-run <svc>` (no -i/-t)","Add `-T` (disable pseudo-TTY) when piping: `docker compose run --dry-run -T svc cmd`","If you must test interactively, run without --dry-run against a throwaway project"],"exampleFix":"# before\ndocker compose run --dry-run -it web sh\n# after\ndocker compose run --dry-run -T web sh","handlingStrategy":"validation","validationCode":"# strip TTY flags when dry-running in scripts\nrun_compose() {\n  if [ \"$1\" = \"--dry-run\" ]; then shift; docker compose --dry-run run -T \"$@\"; else docker compose run \"$@\"; fi\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never combine -it with --dry-run; keep dry-run invocations non-interactive","In CI always use -T for run/exec so terminal allocation is never requested"],"tags":["dry-run","interactive","run","tty"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}