docker/cli · error

tty service logs only supported with --raw

Error message

tty service logs only supported with --raw

What it means

When `docker service logs` targets a TASK (not a service — the service lookup failed with NotFound at line 85, then the task was found at line 88), and that task's container spec has `TTY: true` (line 98), the CLI cannot apply its pretty-printing pipeline (task name resolution, slot padding, detail parsing via stdcopy). TTY container output is raw terminal data that is not multiplexed into stdout/stderr streams. This error fires at logs.go:105-106 when `tty && !opts.raw`, instructing the user to pass `--raw`.

Solutions

  1. Add the `--raw` flag: `docker service logs --raw <task-id>`
  2. Recreate the service without `--tty` if you need pretty-printed, multiplexed logs
  3. Pipe the raw output through your own formatter if custom formatting is needed

Example fix

# before
docker service logs abc123def456
# error: tty service logs only supported with --raw

# after
docker service logs --raw abc123def456
Defensive patterns

Strategy: validation

Validate before calling

// Before fetching task logs, check TTY status
func shouldUseRawForTask(ctx context.Context, c client.APIClient, taskID string) (bool, error) {
    res, err := c.TaskInspect(ctx, taskID, client.TaskInspectOptions{})
    if err != nil {
        return false, err
    }
    return res.Task.Spec.ContainerSpec.TTY, nil
}
// If TTY is true, always pass --raw (opts.raw = true)

Prevention

When it happens

Trigger: Running `docker service logs <task-id>` where the underlying service/task was created with `--tty` (allocating a pseudo-TTY), without passing `--raw`. The code path is: ServiceInspect returns NotFound → TaskInspect succeeds → TTY check fails.

Common situations: A service was created with `--tty` (common for interactive workloads), and an operator runs `docker service logs <task>` expecting formatted output. The pretty-printer cannot parse raw TTY byte streams.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/0d1d10a006c48c4c. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/service/logs.go:106

		res, err := apiClient.TaskInspect(ctx, opts.target, client.TaskInspectOptions{})
		if err != nil {
			if errdefs.IsNotFound(err) {
				// if the task isn't found, rewrite the error to be clear
				// that we looked for services AND tasks and found none
				err = fmt.Errorf("no such task or service: %v", opts.target)
			}
			return err
		}

		tty = res.Task.Spec.ContainerSpec.TTY
		maxLength = getMaxLength(res.Task.Slot)

		// we can't prettify tty logs. tell the user that this is the case.
		// this is why we assign the logs function to a variable and delay calling
		// it. we want to check this before we make the call and checking twice in
		// each branch is even sloppier than this CLI disaster already is
		if tty && !opts.raw {
			return errors.New("tty service logs only supported with --raw")
		}

		// now get the logs
		responseBody, err = apiClient.TaskLogs(ctx, opts.target, client.TaskLogsOptions{
			ShowStdout: true,
			ShowStderr: true,
			Since:      opts.since,
			Timestamps: opts.timestamps,
			Follow:     opts.follow,
			Tail:       opts.tail,
			// get the details if we request it OR if we're not doing raw mode
			// (we need them for the context to pretty print)
			Details: opts.details || !opts.raw,
		})
		if err != nil {
			return err
		}
		defer responseBody.Close()

View on GitHub (pinned to 4f84911bfe)