{"record":{"id":"19aff4ea59ee661f","repo":"pulumi/pulumi","slug":"props-must-be-a-struct-or-map-or-a-pointer-to-a-st","errorCode":null,"errorMessage":"props must be a struct or map or a pointer to a struct or map","messagePattern":"props must be a struct or map or a pointer to a struct or map","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdk/go/pulumi/context.go","lineNumber":1388,"sourceCode":"\tt, name string, id IDInput, props Input, resource CustomResource, packageRef string, opts ...ResourceOption,\n) error {\n\tif t == \"\" {\n\t\treturn errors.New(\"resource type argument cannot be empty\")\n\t} else if name == \"\" {\n\t\treturn errors.New(\"resource name argument (for URN creation) cannot be empty\")\n\t} else if id == nil {\n\t\treturn errors.New(\"resource ID is required for lookup and cannot be empty\")\n\t}\n\n\tif props != nil {\n\t\tpropsType := reflect.TypeOf(props)\n\t\tif propsType.Kind() == reflect.Pointer {\n\t\t\tpropsType = propsType.Elem()\n\t\t}\n\t\t//nolint:staticcheck // Not applying de-morgens law right now\n\t\tif !(propsType.Kind() == reflect.Struct ||\n\t\t\t(propsType.Kind() == reflect.Map && propsType.Key().Kind() == reflect.String)) {\n\t\t\treturn errors.New(\"props must be a struct or map or a pointer to a struct or map\")\n\t\t}\n\t}\n\n\toptions := merge(opts...)\n\tparent := options.Parent\n\tif options.Parent == nil {\n\t\toptions.Parent = ctx.state.stack\n\t}\n\n\t// Before anything else, if there are transformations registered, give them a chance to run to modify the\n\t// user-provided properties and options assigned to this resource.\n\tvar transformations []ResourceTransformation\n\tvar err error\n\tprops, options, transformations, err = applyTransformations(t, name, props, resource, opts, options)\n\tif err != nil {\n\t\treturn err\n\t}\n","sourceCodeStart":1370,"sourceCodeEnd":1406,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/sdk/go/pulumi/context.go#L1370-L1406","documentation":"When props is supplied to a resource read/lookup, the Go SDK reflects on its type: after dereferencing a pointer, it must be a struct or a map with string keys. Any other kind (slice, int, string, map with non-string keys, pointer-to-pointer, etc.) is rejected because the marshaller cannot convert it into the gRPC argument structure.","triggerScenarios":"Passing props like &someSlice, a map[int]string, a struct wrapped in a pointer inside another pointer, or a non-struct/map value to ctx.GetResource's props parameter.","commonSituations":"Passing a []T of results by mistake; using map[string]any via a typed alias with non-string key; double-pointer from an ORM/JSON decode helper.","solutions":["Pass a plain struct value/pointer or a map with string keys (e.g. map[string]interface{}).","Dereference extra pointer levels before passing (props must be T, *T, **T will fail).","Pass nil if the lookup needs no properties — the check only runs when props != nil."],"exampleFix":"// before\nprops := []string{\"a\", \"b\"}\nctx.GetResource(tok, name, id, props)\n// after\nprops := map[string]interface{}{\"keys\": []string{\"a\", \"b\"}}\nctx.GetResource(tok, name, id, props)","handlingStrategy":"type-guard","validationCode":"func validProps(p interface{}) bool {\n    if p == nil { return true }\n    t := reflect.TypeOf(p)\n    for t.Kind() == reflect.Pointer { t = t.Elem() }\n    return t.Kind() == reflect.Struct ||\n        (t.Kind() == reflect.Map && t.Key().Kind() == reflect.String)\n}","typeGuard":"func validProps(p interface{}) bool {\n    t := reflect.TypeOf(p)\n    for t != nil && t.Kind() == reflect.Pointer { t = t.Elem() }\n    if t == nil { return true }\n    return t.Kind() == reflect.Struct ||\n        (t.Kind() == reflect.Map && t.Key().Kind() == reflect.String)\n}","tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"props must be a struct or map\") {\n        return fmt.Errorf(\"bad props for %s lookup: %w\", name, err)\n    }\n    return err\n}","preventionTips":["Use typed structs or map[string]T for lookup props","Strip extra pointer indirection before passing props","Pass nil rather than an arbitrary value when props are not needed"],"tags":["go-sdk","pulumi","reflection","type-mismatch"],"backgroundTag":"invalid-argument-type","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}