derailed/k9s · error

failed to maintain log stream after %d retries

Error message

failed to maintain log stream after %d retries

What it means

The tailing goroutine behind Pod log streaming retries the request with exponential backoff, stopping early only when the pod is detected terminating/deleted. When the retry budget (logRetryCount) is exhausted without a stable stream, it pushes this error into the channel as an ErrLogItem rather than hanging or panicking.

Source

Thrown at internal/dao/pod.go:465

				case <-ctx.Done():
					return
				case <-time.After(delay):
					if delay = backoffCtx.NextBackOff(); delay == backoff.Stop {
						return
					}
				}
				continue
			case streamCanceled:
				return
			}

			// Reset backoff and delay on successful connection
			bf.Reset()
			delay = logBackoffInitial
		}

		// Out of retries
		out <- opts.ToErrLogItem(fmt.Errorf("failed to maintain log stream after %d retries", logRetryCount))
	}()

	go func() {
		wg.Wait()
		close(out)
	}()

	return out
}

func readLogs(ctx context.Context, stream io.ReadCloser, out chan<- *LogItem, opts *LogOptions) streamResult {
	defer func() {
		if err := stream.Close(); err != nil && !errors.Is(err, io.ErrClosedPipe) {
			slog.Error("Failed to close stream",
				slogs.Container, opts.Info(),
				slogs.Error, err,
			)
		}

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Check connectivity to the API server, then restart the log tail/view
  2. Verify the pod still exists and is not stuck Terminating: kubectl get pod <p> -o wide
  3. Stabilize the path (VPN, LB idle timeouts > read interval) instead of only retrying harder
Defensive patterns

Strategy: retry

Validate before calling

// Before opening a long tail, confirm the pod exists and the API answers
if podDAO.shouldStopRetrying(path) { return nil }
if _, err := podDAO.GetInstance(fqn); err != nil { return err }

Try / catch

for item := range podDAO.Logs(ctx, opts) {
    if item.IsErr && strings.Contains(item.Message, "failed to maintain log stream") {
        // re-open the stream after a pause; stop after N user-level retries
    }
}

Prevention

When it happens

Trigger: The API-server log endpoint stays unreachable for the entire backoff window: network drops, API server restarts, proxy/LB idle timeouts killing streams, or a pod stuck Terminating that shouldStopRetrying does not recognize.

Common situations: Laptop sleep/resume with a log tail open; VPN or relay to the cluster dropping; heavily loaded control planes timing out on log requests; long-running tails behind aggressive load balancers.

Related errors


AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15). Data as JSON: /api/errors/73d1c016a27e3986. Report an issue: GitHub.