hashicorp/terraform · critical

NewResourceConfigShimmed given %#v; an object type is requir

Error message

NewResourceConfigShimmed given %#v; an object type is required

What it means

Panics in NewResourceConfigShimmed (resource.go:139). It wraps a cty.Value into a legacy ResourceConfig and requires val.Type().IsObjectType(); passing a non-object value (primitive, list, map, tuple) panics. The docstring states it will panic if the value is not an object type.

Source

Thrown at internal/legacy/terraform/resource.go:139

		Config: cfg,

		ComputedKeys: newResourceConfigShimmedComputedKeys(v, ""),
	}
}

// NewResourceConfigShimmed wraps a cty.Value of object type in a legacy
// ResourceConfig object, so that it can be passed to older APIs that expect
// this wrapping.
//
// The returned ResourceConfig is already interpolated and cannot be
// re-interpolated. It is, therefore, useful only to functions that expect
// an already-populated ResourceConfig which they then treat as read-only.
//
// If the given value is not of an object type that conforms to the given
// schema then this function will panic.
func NewResourceConfigShimmed(val cty.Value, schema *configschema.Block) *ResourceConfig {
	if !val.Type().IsObjectType() {
		panic(fmt.Errorf("NewResourceConfigShimmed given %#v; an object type is required", val.Type()))
	}
	ret := &ResourceConfig{}

	legacyVal := hcl2shim.ConfigValueFromHCL2Block(val, schema)
	if legacyVal != nil {
		ret.Config = legacyVal

		// Now we need to walk through our structure and find any unknown values,
		// producing the separate list ComputedKeys to represent these. We use the
		// schema here so that we can preserve the expected invariant
		// that an attribute is always either wholly known or wholly unknown, while
		// a child block can be partially unknown.
		ret.ComputedKeys = newResourceConfigShimmedComputedKeys(val, "")
	} else {
		ret.Config = make(map[string]interface{})
	}
	ret.Raw = ret.Config

View on GitHub (pinned to c9def3e214)

Solutions

  1. Pass a cty.Value of object type built to conform to the schema block (use cty.ObjectVal or configschema-derived types).
  2. Check val.Type().IsObjectType() before calling, and wrap/convert when needed.
  3. Use hcl2shim.ConfigValueFromHCL2Block to produce the correct object shape.

Example fix

// before
cfg := NewResourceConfigShimmed(cty.StringVal("hi"), schema)
// after
cfg := NewResourceConfigShimmed(cty.ObjectVal(map[string]cty.Value{"name": cty.StringVal("hi")}), schema)
Defensive patterns

Strategy: type-guard

Validate before calling

func shimConfigSafe(val cty.Value, schema *configschema.Block) (*terraform.ResourceConfig, error) {
    if !val.Type().IsObjectType() {
        return nil, fmt.Errorf("expected object type, got %s", val.Type().FriendlyName())
    }
    return terraform.NewResourceConfigShimmed(val, schema), nil
}

Type guard

func isCtyObject(v cty.Value) bool { return v.Type().IsObjectType() }

Prevention

When it happens

Trigger: Calling NewResourceConfigShimmed with a cty.Value that is not an object — e.g. passing a single attribute value (cty.StringVal) or a list/tuple where a block-level object is expected.

Common situations: Provider/plugin integration code shimming cty values incorrectly, or passing a nested attribute value instead of the full block object.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/5f0e08121113dcc9. Report an issue: GitHub.