pulumi/pulumi · error

expected a %v, got a %s

Error message

expected a %v, got a %s

What it means

While copying a known property value into a destination whose Input interface resolves to a bool-based concrete type, the property value is not a boolean. The guard `v.IsBool()` fails before `SetBool` is called, protecting against reflect panics.

Source

Thrown at sdk/go/pulumi/provider.go:433

			return err
		}
		dest.Set(result)
		return nil
	}

	if dest.Type().Implements(inputType) {
		// Try to determine the input type from the interface.
		if it := internal.InputInterfaceTypeToConcreteType(dest.Type()); it != nil {
			inputType := it
			for inputType.Kind() == reflect.Pointer {
				inputType = inputType.Elem()
			}

			//nolint:exhaustive // We only need to process a few types here.
			switch inputType.Kind() {
			case reflect.Bool:
				if !v.IsBool() {
					return fmt.Errorf("expected a %v, got a %s", inputType, v.TypeString())
				}
				result := reflect.New(inputType).Elem()
				result.SetBool(v.BoolValue())
				dest.Set(result)
				return nil
			case reflect.Int:
				if !v.IsNumber() {
					return fmt.Errorf("expected an %v, got a %s", inputType, v.TypeString())
				}
				result := reflect.New(inputType).Elem()
				result.SetInt(int64(v.NumberValue()))
				dest.Set(result)
				return nil
			case reflect.Float64:
				if !v.IsNumber() {
					return fmt.Errorf("expected an %v, got a %s", inputType, v.TypeString())
				}
				result := reflect.New(inputType).Elem()

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Fix the provider or resource so the property is serialized as an actual boolean
  2. Change the destination struct field to pulumi.StringInput (or the actual emitted type) and convert explicitly
  3. Coerce the value at the source (e.g. strconv.ParseBool) before it is wrapped into a PropertyValue
  4. Verify provider/SDK schema versions are in sync; regenerate the typed SDK

Example fix

// before
Enabled pulumi.BoolInput `pulumi:"enabled"` // provider returns "true" as string
// after
Enabled pulumi.StringInput `pulumi:"enabled"`
// then: pulumi.Bool(strings.EqualFold(enabled, "true"))
Defensive patterns

Strategy: validation

Validate before calling

if b, ok := rawValue.(bool); !ok {
    return fmt.Errorf("property %q must be a bool, got %T", name, rawValue)
}

Type guard

func isBoolProperty(v resource.PropertyValue) bool { return v.IsBool() }

Try / catch

if err := copyInputTo(ctx, v, dest); err != nil {
    var te *TypeError
    if errors.As(err, &te) { /* normalize bool-like strings with strconv.ParseBool */ }
    return err
}

Prevention

When it happens

Trigger: copyInputTo receives a PropertyValue that is a string, number, object, etc., while the destination type's Input concrete type has reflect.Kind Bool (e.g. pulumi.BoolInput / pulumi.BoolPtrInput fields), typically inside copyToStruct unmarshaling of an InvokeResult or typed asset value.

Common situations: A provider returns a boolean property as a string ("true") or as a number (0/1); schema drift between the provider's serialized output and the generated Go SDK types; hand-written structs whose ElementType maps to bool while the data is textual.

Related errors


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