pulumi/pulumi · error

hooks must be an object mapping hook types to command lists

Error message

hooks must be an object mapping hook types to command lists

What it means

The resourceHooks option must be an object mapping hook types (e.g. beforeCreate, afterUpdate) to arrays of hook names. This error is thrown when the evaluated hooks value is not a cty object (e.g. a string or array), before populating the ResourceHooksBinding.

Source

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

					}
					hdopt = append(hdopt, v.StringValue())
				}
				request.HideDiffs = hdopt
			}
		}

		// Process hooks - register command hooks and build the hooks binding
		if res.Options.Hooks != nil {
			hooksVal, poison, diags := evalCtx.Evaluate(res.Options.Hooks)
			if poison != nil {
				return makePoisonValue(*poison), nil
			}
			if diags.HasErrors() {
				return cty.NilVal, diags
			}
			if !hooksVal.IsNull() && !hooksVal.IsComputed() {
				if !hooksVal.IsObject() {
					return cty.NilVal, errors.New("hooks must be an object mapping hook types to command lists")
				}
				binding := &pulumirpc.RegisterResourceRequest_ResourceHooksBinding{}
				for hookType, commandLists := range hooksVal.ObjectValue() {
					if commandLists.IsNull() || commandLists.IsComputed() {
						continue
					}
					if !commandLists.IsArray() {
						return cty.NilVal, fmt.Errorf("hooks.%s must be an array of hooks", hookType)
					}
					var hookNames []string
					for idx, hookVal := range commandLists.ArrayValue() {
						if hookVal.IsNull() || hookVal.IsComputed() {
							continue
						}
						if !hookVal.IsString() {
							return cty.NilVal, fmt.Errorf("hooks.%s[%d] must be a reference to a named hook block", hookType, idx)
						}
						hookNames = append(hookNames, hookVal.StringValue())

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Structure the value as an object: options { resourceHooks: { beforeCreate: ["my-hook"] } }
  2. Use valid hook-type keys mapping to arrays of hook names
  3. Ensure the value is an object literal, not a string or list

Example fix

// before
options = { resourceHooks: "my-hook" }
// after
options = { resourceHooks: { beforeCreate: ["my-hook"] } }
Defensive patterns

Strategy: validation

Validate before calling

if h, ok := opts["resourceHooks"]; ok && h != nil {
    if _, isMap := h.(map[string]any); !isMap {
        return fmt.Errorf("resourceHooks must be an object of hook type -> hook list")
    }
}

Type guard

func isHookBinding(v any) bool {
    _, ok := v.(map[string]any)
    return ok
}

Prevention

When it happens

Trigger: Passing options {resourceHooks: "my-hook"} or a list instead of an object in a PCL program (interpreter.go:1866).

Common situations: Specifying a single hook without the hook-type wrapper object; copying YAML hooks config directly as a list; confusing hook names with the hook-type map.

Related errors


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