kubernetes/kops · error

error writing to output: %v

Error message

error writing to output: %v

What it means

At the end of a dry-run `kops update cluster`, the generated summary buffer (cluster changes, must-remove items, instance restart notes) is written to the command's output writer. If that write fails, the command returns `error writing to output: %v`. This is an I/O failure of the destination stream, not a cluster problem.

Source

Thrown at cmd/kops/update_cluster.go:497

				} else {
					fmt.Fprintf(sb, " * to ssh to the bastion, you probably want to configure a bastionPublicName.\n")
				}
			}
			fmt.Fprintf(sb, " * the ubuntu user is specific to Ubuntu. If not using Ubuntu please use the appropriate user based on your OS.\n")
			fmt.Fprintf(sb, " * read about installing addons at: https://kops.sigs.k8s.io/addons.\n")
			fmt.Fprintf(sb, "\n")
		}

		if !firstRun && !c.Reconcile {
			// TODO: Detect if rolling-update is needed
			fmt.Fprintf(sb, "\n")
			fmt.Fprintf(sb, "Changes may require instances to restart: kops rolling-update cluster\n")
			fmt.Fprintf(sb, "\n")
		}

		_, err := out.Write(sb.Bytes())
		if err != nil {
			return nil, fmt.Errorf("error writing to output: %v", err)
		}
	}

	return results, nil
}

func parseLifecycle(lifecycle string) (fi.Lifecycle, error) {
	if v, ok := fi.LifecycleNameMap[lifecycle]; ok {
		return v, nil
	}
	return "", fmt.Errorf("unknown lifecycle %q, available lifecycle: %s", lifecycle, strings.Join(fi.Lifecycles.List(), ","))
}

func usesBastion(instanceGroups []*kops.InstanceGroup) bool {
	for _, ig := range instanceGroups {
		if ig.Spec.Role.HasBastion() {
			return true
		}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Redirect full output to a file instead of piping into commands that exit early (`kops update cluster ... --dry-run > plan.txt`), then inspect the file
  2. Retry when the output destination (disk/pipe) is healthy
  3. Fix the embedder's writer lifecycle if calling RunUpdateCluster programmatically (keep writer open, flush/close in order)

Example fix

// before
kops update cluster c.k8s.local --dry-run | head -5
// after
kops update cluster c.k8s.local --dry-run > plan.txt
head -5 plan.txt
Defensive patterns

Strategy: try-catch

Try / catch

results, err := RunUpdateCluster(ctx, options)
if errors.Is(err, syscall.EPIPE) || strings.Contains(err.Error(), "error writing to output") {
	// output stream died (e.g. SIGPIPE); rerun writing to a file
	f, _ := os.Create("plan.txt")
	defer f.Close()
	options.Out = f
	results, err = RunUpdateCluster(ctx, options)
}
if err != nil { return err }

Prevention

When it happens

Trigger: out.Write fails because the underlying writer broke: closed stdout pipe (e.g. `kops update cluster --dry-run | head` causing SIGPIPE/EPIPE), full disk, or the caller (test harness / RunCreateCluster / RunGetAssets) supplied a writer on a closed file or network stream.

Common situations: Piping kops output to `head` or `grep -q` which close the pipe early; CI log collection dropping the stream; running under systemd with a journald that blocks; buffered writers not flushed/closed by embedders.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/070b934b493668b5. Report an issue: GitHub.