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
- 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
- Retry when the output destination (disk/pipe) is healthy
- 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
- Avoid piping kops output into commands that exit early (head, grep -q); redirect to a file instead
- Ensure stdout/stderr destinations in CI remain open for the process lifetime
- For embedders, pass an io.Writer you control and flush/close it after RunUpdateCluster returns
- Check disk space on hosts capturing large dry-run output
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
- error writing to output: %v
- unable to execute --dry-run without setting --output
- error writing cluster yaml to stdout: %v
- error writing cluster json to stdout: %v
- unsupported output type %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/070b934b493668b5.
Report an issue: GitHub.