hasura/graphql-engine · error

writing output failed: %w

Error message

writing output failed: %w

What it means

This error is returned by writeByOutputFormat in the Hasura CLI when streaming the formatted JSON metadata output to the destination writer (usually stdout) fails during io.Copy. It wraps the underlying I/O error, so the real cause (broken pipe, closed stdout, disk full when redirected) is in the wrapped error chain. It only occurs in the rawOutputFormatJSON branch after the metadata has been successfully exported and indented.

Source

Thrown at cli/commands/metadata.go:113

	return metadataCmd
}

func writeByOutputFormat(w io.Writer, b []byte, format rawOutputFormat) error {
	var op errors.Op = "commands.writeByOutputFormat"

	switch format {
	case rawOutputFormatJSON:
		out := new(bytes.Buffer)

		err := json.Indent(out, b, "", "  ")
		if err != nil {
			return errors.E(op, err)
		}

		_, err = io.Copy(w, out)
		if err != nil {
			return errors.E(op, fmt.Errorf("writing output failed: %w", err))
		}
	case rawOutputFormatYAML:
		o, err := metadatautil.JSONToYAML(b)
		if err != nil {
			return errors.E(op, err)
		}

		_, err = io.Copy(w, bytes.NewReader(o))
		if err != nil {
			return errors.E(op, fmt.Errorf("writing output failed: %w", err))
		}
	default:
		return errors.E(
			op,
			fmt.Errorf(
				"output format '%v' is not supported. supported formats: %v, %v",
				format,
				rawOutputFormatJSON,

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Inspect the wrapped error with errors.Unwrap or go-errors chain to identify the actual I/O cause (EPIPE, no space left on device, file already closed)
  2. If piping to pagers like head/less, use a pager that reads all input or capture to a file first: `hasura metadata export > metadata.json`
  3. Free disk space or redirect to a writable location if the destination filesystem is full
  4. Avoid closing ec.Stdout before metadata commands finish when embedding the CLI programmatically

Example fix

# before
hasura metadata export --output-format json | head -20
# after (EPIPE from head exiting early)
hasura metadata export --output-format json > metadata.json && head -20 metadata.json
Defensive patterns

Strategy: try-catch

Try / catch

// Go: capture and inspect the wrapped io error
err := writeByOutputFormat(ec.Stdout, b, rawOutputFormatJSON)
if err != nil {
  var opErr *net.OpError
  if errors.As(err, &opErr) || strings.Contains(err.Error(), "broken pipe") {
    // consumer exited early; not fatal for batch flows
    log.Println("output consumer closed early:", err)
    return nil
  }
  return err
}

Prevention

When it happens

Trigger: Running `hasura metadata export --output-format json` (or code calling writeByOutputFormat with rawOutputFormatJSON) where the destination writer fails mid-copy: piping output to a command that exits early (`hasura metadata export | head`), redirecting to a full filesystem, or stdout being closed by the calling process.

Common situations: Piping CLI output to `head`/`less` that terminates early (EPIPE), writing to a redirected file on a full disk, running in CI where stdout is captured and the runner is killed, or programmatic use of the EC writer after it was already closed.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/1051d69b2bbe32f8. Report an issue: GitHub.