GoogleContainerTools/skaffold · warning

reading bytes from log stream: %w

Error message

reading bytes from log stream: %w

What it means

While consuming a container's log stream, stream.go reads lines from the stream reader. If the underlying read fails (not a clean EOF), the error is wrapped so the caller knows bytes could not be read from the log stream. Clean EOFs are handled upstream as normal stream end; this error represents a real I/O failure.

Source

Thrown at pkg/skaffold/log/stream/stream.go:52

		select {
		case <-ctx.Done():
			olog.Entry(ctx).Infof("%s interrupted", formatter.Name())
			return nil
		default:
			// Read up to newline
			line, err := r.ReadString('\n')
			// As per https://github.com/kubernetes/kubernetes/blob/017b359770e333eacd3efcb4174f1d464c208400/test/e2e/storage/podlogs/podlogs.go#L214
			// Filter out the expected "end of stream" error message and
			// attempts to read logs from a container that was deleted due to re-deploy or
			// attempts to read logs from a container that is not ready yet.
			if err == io.EOF {
				if !isEmptyOrContainerNotReady(line) {
					formatter.PrintLine(out, line)
				}
				return nil
			}
			if err != nil {
				return fmt.Errorf("reading bytes from log stream: %w", err)
			}
			formatter.PrintLine(out, line)
		}
	}
}

func isEmptyOrContainerNotReady(line string) bool {
	return line == "" ||
		strings.HasPrefix(line, "rpc error: code = Unknown desc = Error: No such container:") ||
		strings.HasPrefix(line, "unable to retrieve container logs for ") ||
		strings.HasPrefix(line, "Unable to retrieve container logs for ")
}

View on GitHub (pinned to a1189de023)

Solutions

  1. Check cluster/pod health (kubectl get pod) and restart skaffold dev to re-establish the stream
  2. For expected cancellations, treat errors.Is(err, context.Canceled) as normal shutdown and ignore
  3. Improve network stability (VPN, keepalives) or lower log volume with container-stdin/false filters
  4. Upgrade skaffold/client if the stream reader has a known idle-timeout bug

Example fix

// caller-side handling
if err := streamContainerLogs(...); err != nil {
    if errors.Is(err, context.Canceled) || strings.Contains(err.Error(), "reading bytes from log stream") && isShutdown(err) {
        return nil // expected during teardown
    }
    return err
}
Defensive patterns

Strategy: retry

Type guard

func isTransientStreamError(err error) bool {
    if errors.Is(err, context.Canceled) || errors.Is(err, io.ErrUnexpectedEOF) {
        return true
    }
    var ne net.Error
    return errors.As(err, &ne)
}

Try / catch

err := streamContainerLogs(ctx, req)
if err != nil && strings.Contains(err.Error(), "reading bytes from log stream") {
    if ctx.Err() != nil { return nil } // shutdown, ignore
    if isTransientStreamError(err) {
        return retryWithBackoff(3, time.Second, func() error { return streamContainerLogs(ctx, req) })
    }
    return err
}

Prevention

When it happens

Trigger: The bufio/scanner read over the pod log stream returns a non-EOF error: container/API connection dropped, context canceled mid-read, API server closed the watch/connection abnormally, or decompression/decode failure on the stream.

Common situations: Pod deleted or node rebooted mid 'skaffold dev' while logs stream; network drop to the cluster; Kubernetes context canceled by Ctrl-C racing the reader; long-lived stream hitting connection idle timeouts.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/216fb967107b9e46. Report an issue: GitHub.