hashicorp/nomad · error

failed to generate command UI

Error message

failed to generate command UI

What it means

NewWriterUI walks a cli.Ui chain (ColoredUi -> BasicUi/MockUi) to extract raw reader/writer streams. If the loop exits without resolving a supported base UI (because the chain ends in a nil Ui or was empty), it throws this sentinel error. It means no *cli.BasicUi or *cli.MockUi was found at the bottom of the UI chain.

Source

Thrown at command/ui/writer_ui.go:67

			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) }

func (w *WriterUI) Ask(query string) (string, error)       { return w.Ui.Ask(query) }
func (w *WriterUI) AskSecret(query string) (string, error) { return w.Ui.AskSecret(query) }

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the UI chain terminates in a *cli.BasicUi (production) or *cli.MockUi (tests)
  2. If using ColoredUi, verify it wraps a BasicUi via its .Ui field
  3. Check that the cli.Ui passed to NewWriterUI is non-nil
  4. Wrap any custom Ui implementations so they expose an underlying BasicUi

Example fix

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

Strategy: type-guard

Validate before calling

func canWrapWriterUI(u cli.Ui) bool {
	switch v := u.(type) {
	case *cli.BasicUi, *cli.MockUi:
		return true
	case *cli.ColoredUi:
		return canWrapWriterUI(v.Ui)
	default:
		return false
	}
}
if !canWrapWriterUI(myUi) { /* fix UI construction before calling NewWriterUI */ }

Type guard

func isWriterUICompatible(u cli.Ui) bool {
	for u != nil {
		switch t := u.(type) {
		case *cli.BasicUi, *cli.MockUi:
			return true
		case *cli.ColoredUi:
			u = t.Ui
		default:
			return false
		}
	}
	return false
}

Try / catch

wUI, err := ui.NewWriterUI(u)
if err != nil {
	if err.Error() == "failed to generate command UI" {
		// fall back to the plain cli.Ui instead of raw stream access
	}
	return err
}

Prevention

When it happens

Trigger: Passing nil to NewWriterUI; passing a Ui chain whose base is not *cli.BasicUi or *cli.MockUi (e.g. a custom cli.Ui implementation or a wrapped Ui other than cli.ColoredUi).

Common situations: Custom UI wrappers injected into the Vault command framework that don't unwrap to BasicUi; tests constructing a WriterUI with a MockUi nested incorrectly or no UI at all; running commands in environments where the UI was replaced by a non-standard implementation.

Related errors


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