hashicorp/nomad · error

writer ui: unsupported Ui type: %T

Error message

writer ui: unsupported Ui type: %T

What it means

NewWriterUI wraps an existing mitchellh/cli.Ui so command output can be redirected to custom writers. It only understands *cli.BasicUi and *cli.ColoredUi; anything else falls into the type-switch default and this error is returned. It exists to fail fast when an unsupported Ui implementation is passed instead of silently mis-routing output.

Source

Thrown at command/ui/writer_ui.go:62

		}

		switch u := ui.(type) {
		case *cli.MockUi:
			wUI.reader = u.InputReader
			wUI.writer = u.OutputWriter
			wUI.errorWriter = u.ErrorWriter
			wUI.baseUi = u
			done = true
		case *cli.BasicUi:
			wUI.reader = u.Reader
			wUI.writer = u.Writer
			wUI.errorWriter = u.ErrorWriter
			wUI.baseUi = u
			done = true
		case *cli.ColoredUi:
			ui = u.Ui
		default:
			return nil, fmt.Errorf("writer ui: unsupported Ui type: %T", ui)
		}
	}

	if !done {
		return nil, errors.New("failed to generate command UI")
	}

	return &wUI, nil
}

func (w *WriterUI) InputReader() io.Reader  { return w.reader }
func (w *WriterUI) OutputWriter() io.Writer { return w.writer }
func (w *WriterUI) ErrorWriter() io.Writer  { return w.errorWriter }

func (w *WriterUI) Output(message string) { w.Ui.Output(message) }
func (w *WriterUI) Info(message string)   { w.Ui.Info(message) }
func (w *WriterUI) Warn(message string)   { w.Ui.Warn(message) }
func (w *WriterUI) Error(message string)  { w.Ui.Error(message) }

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Pass a *cli.BasicUi or *cli.ColoredUi to NewWriterUI (wrap your custom Ui's Writer/Reader/ErrorWriter fields into a *cli.BasicUi instead)
  2. If you own a custom Ui type, extend the type switch in writer_ui.go to handle it, mapping its writer fields onto the WriterUI struct
  3. Check that you are not passing a typed-nil or incorrectly typed interface value; print %T of the argument to confirm its concrete type

Example fix

// before
wUI, err := NewWriterUI(&myCustomUi{w: os.Stdout})
// after
wUI, err := NewWriterUI(&cli.BasicUi{Writer: os.Stdout, ErrorWriter: os.Stderr, Reader: os.Stdin})
Defensive patterns

Strategy: type-guard

Validate before calling

func isSupportedUI(u cli.Ui) bool {
	switch u.(type) {
	case *cli.BasicUi, *cli.ColoredUi:
		return true
	}
	return false
}
// call site:
if !isSupportedUI(myUi) { /* wrap into *cli.BasicUi first */ }

Type guard

func asBasicUi(u cli.Ui) (*cli.BasicUi, bool) {
	if bu, ok := u.(*cli.BasicUi); ok { return bu, true }
	if cu, ok := u.(*cli.ColoredUi); ok {
		return &cli.BasicUi{Reader: cu.Reader, Writer: cu.Writer, ErrorWriter: cu.ErrorWriter}, true
	}
	return nil, false
}

Prevention

When it happens

Trigger: Calling NewWriterUI with a Ui that is neither *cli.BasicUi nor *cli.ColoredUi — e.g. a custom cli.Ui implementation, a wrapped/proxy Ui type, or a typed nil interface. The test TestWriterUI_AskSecret covers the supported path; any third-party Ui hits the default branch.

Common situations: Embedding the library in a TUI or test harness that supplies its own cli.Ui implementation; passing a Ui wrapped in another struct; refactors that changed the concrete Ui type previously passed (e.g. ColoredUi replaced with a custom type).

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/9f95c79f84b993eb. Report an issue: GitHub.