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
- Structure the value as an object: options { resourceHooks: { beforeCreate: ["my-hook"] } }
- Use valid hook-type keys mapping to arrays of hook names
- 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
- Always wrap hooks in an object keyed by hook type (beforeCreate, afterUpdate, ...)
- Convert YAML hook lists into the hook-type map form when porting
- Validate the shape of the hooks option before running the program
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
- hooks.%s must be an array of hooks
- hook %s: command must be a list of strings
- hook %s: command elements must be strings was %v
- aliases must be an array of strings or alias objects
- %s must be a string
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/8d2f8c9c930e8492.
Report an issue: GitHub.