hashicorp/terraform · critical

unexpected empty message for init message code: %s

Error message

unexpected empty message for init message code: %s

What it means

This panic fires in InitHuman.prepareMessage when an InitMessageCode resolves to a MessageRegistry entry whose HumanValue is the empty string. The registry must have a human-readable template for every code, so an empty HumanValue means the registry was extended with a code but no human text.

Source

Thrown at internal/command/views/init.go:227

// prints the formatted message to the stdout stream.
func (v *InitHuman) print(message string) {
	message = v.view.colorize.Color(strings.TrimSpace(message))
	v.view.streams.Println(message)
}

// prepareMessage retrieves a message template matching the InitMessageCode and
// returns a formatted string made using the template and param argument(s).
//
// As this is implemented on InitHuman the human message template is used.
func (v *InitHuman) prepareMessage(messageCode InitMessageCode, params ...any) string {
	message, ok := MessageRegistry[messageCode]
	if !ok {
		// display the message code as fallback if not found in the message registry
		return string(messageCode)
	}

	if message.HumanValue == "" {
		panic("unexpected empty message for init message code: " + string(messageCode))
	}

	return fmt.Sprintf(message.HumanValue, params...)
}

// The InitJSON implementation renders streaming JSON logs, suitable for
// integrating with other software.
type InitJSON struct {
	view *JSONView
}

var (
	_ Init                       = (*InitJSON)(nil)
	_ ProviderInstallationLogger = (*InitJSON)(nil)
)

func (v *InitJSON) Diagnostics(diags tfdiags.Diagnostics) {
	v.view.Diagnostics(diags)

View on GitHub (pinned to d32a084675)

Solutions

  1. Search MessageRegistry in views/init.go for the code printed in the panic; fill in a non-empty HumanValue template.
  2. Add a test that iterates all InitMessageCode values and asserts MessageRegistry[code].HumanValue != "".
  3. If the code should not have a human form, do not register it (or restructure so prepareMessage is never called for it).

Example fix

// before
MessageRegistry[InitSomeNewCode] = InitMessage{
  HumanValue: "",
  JSONValue:  "some json template",
}
// after
MessageRegistry[InitSomeNewCode] = InitMessage{
  HumanValue: "Initializing some new thing...",
  JSONValue:  "some json template",
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the registry on init.
for code, msg := range MessageRegistry {
  if msg.HumanValue == "" {
    panic("registry missing HumanValue for " + string(code)) // fail fast at boot
  }
}

Type guard

// n/a — string emptiness check

Prevention

When it happens

Trigger: `terraform init` (human output) emits a registered InitMessageCode whose MessageRegistry entry has HumanValue="". Reached when a maintainer adds a code to the InitMessageCode type and a registry row, but leaves HumanValue blank, and init then tries to display it.

Common situations: A maintainer adds a new init message code and forgets to fill in (or accidentally empties) the HumanValue field. Triggered the first time init renders that message during a normal `terraform init`.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/cbb64010613c51bc. Report an issue: GitHub.