pulumi/pulumi · error

protect must be a boolean or null

Error message

protect must be a boolean or null

What it means

The PCL interpreter evaluates the `protect` resource option and requires it to be a boolean or null. Any other concrete type (string "true", number, object) triggers this error and stops evaluation of the resource registration.

Source

Thrown at pkg/pcl/runtime/interpreter.go:1593

				}
				request.IgnoreChanges = icopt
			}
		}
		if res.Options.Protect != nil {
			protect, poison, diags := evalCtx.Evaluate(res.Options.Protect)
			if poison != nil {
				return makePoisonValue(*poison), nil
			}
			if diags.HasErrors() {
				return cty.NilVal, diags
			}
			if !protect.IsComputed() {
				var popt *bool
				if protect.IsBool() {
					b := protect.BoolValue()
					popt = &b
				} else if !protect.IsNull() {
					return cty.NilVal, errors.New("protect must be a boolean or null")
				}
				request.Protect = popt
			}
		}
		if res.Options.ReplaceWith != nil {
			replaceWith, poison, diags := evalCtx.Evaluate(res.Options.ReplaceWith)
			if poison != nil {
				return makePoisonValue(*poison), nil
			}
			if diags.HasErrors() {
				return cty.NilVal, diags
			}
			if !replaceWith.IsNull() && !replaceWith.IsComputed() {
				if !replaceWith.IsArray() {
					return cty.NilVal, errors.New("replaceWith must be an array of resources")
				}
				var rwopt []string
				for _, v := range replaceWith.ArrayValue() {

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Use a bare boolean literal: protect = true or protect = false.
  2. Unquote string booleans: "true" -> true.
  3. Convert upstream strings to bools before passing (e.g. in the producing code or with a boolean-typed variable).
  4. Pass null (or omit/leave computed) if protection is conditional at runtime.

Example fix

// before (PCL)
options { protect = "true" }
// after
options { protect = true }
Defensive patterns

Strategy: type-guard

Validate before calling

func validateProtect(v any) error {
	switch t := v.(type) {
	case nil, bool:
		return nil
	default:
		return fmt.Errorf("protect must be bool, got %T", t)
	}
}

Type guard

func isBoolOrNull(v cty.Value) bool {
	return v.IsNull() || v.Type() == cty.Bool
}

Try / catch

if err != nil && strings.Contains(err.Error(), "protect must be a boolean or null") {
	return fmt.Errorf("check the 'protect' option: use unquoted true/false: %w", err)
}

Prevention

When it happens

Trigger: Passing `options { protect = "true" }` (string) or any non-bool, non-null value in `__opts.protect` to registerResource in pkg/pcl/runtime.

Common situations: Users quoting booleans when converting from YAML/JSON configs (`protect: "false"`), or binding protect to a variable typed as string instead of bool.

Related errors


AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31). Data as JSON: /api/errors/47a8bb1940d15178. Report an issue: GitHub.