pulumi/pulumi · error
expected a %s, got an asset
Error message
expected a %s, got an asset
What it means
unmarshalOutput writes a wire property value into a reflect destination (e.g. a typed result struct for a resource method's outputs). When the value is an Asset, the destination type must be assignable from the SDK's Asset interface (assetType); otherwise the SDK refuses with 'expected a %s, got an asset' (rpc.go:822), naming the destination type it actually received.
Source
Thrown at sdk/go/pulumi/rpc.go:822
// pointer allocation to preserve the nil zero value for pointer destinations.
if v.IsOutput() && v.OutputValue().Element.IsNull() {
return v.OutputValue().Secret, nil
}
allocatedPointer := false
// Allocate storage as necessary.
for dest.Kind() == reflect.Pointer {
allocatedPointer = true
elem := reflect.New(dest.Type().Elem())
dest.Set(elem)
dest = elem.Elem()
}
// In the case of assets and archives, turn these into real asset and archive structures.
switch {
case v.IsAsset():
if !assetType.AssignableTo(dest.Type()) {
return false, fmt.Errorf("expected a %s, got an asset", dest.Type())
}
asset, secret, err := unmarshalPropertyValue(ctx, v)
if err != nil {
return false, err
}
dest.Set(reflect.ValueOf(asset))
return secret, nil
case v.IsArchive():
if !archiveType.AssignableTo(dest.Type()) {
return false, fmt.Errorf("expected a %s, got an archive", dest.Type())
}
archive, secret, err := unmarshalPropertyValue(ctx, v)
if err != nil {
return false, err
}
dest.Set(reflect.ValueOf(archive))View on GitHub (pinned to 793f7b2e16)
Solutions
- Change the destination field's type to pulumi.Asset (or the concrete asset type) so it is assignable from assetType.
- Regenerate or update the provider's Go SDK so result structs match the schema's asset-typed properties.
- If the value should be a string, extract it at the call site from the concrete asset (e.g. type-switch to *FileAsset/*StringAsset/*RemoteAsset) rather than typing the field as string.
- Check the provider schema (`pulumi schema`) to confirm the property's expected type and align the struct.
Example fix
// before
type GetResult struct {
Content string
}
// after
type GetResult struct {
Content pulumi.Asset
} Defensive patterns
Strategy: type-guard
Validate before calling
func expectsAsset(dest reflect.Value, v resource.PropertyValue) bool {
return !v.IsAsset() || reflect.TypeOf((*pulumi.Asset)(nil)).Elem().AssignableTo(dest.Type())
} Type guard
func destAcceptsAsset(destType reflect.Type) bool {
return reflect.TypeOf((*pulumi.Asset)(nil)).Elem().AssignableTo(destType)
} Try / catch
if err := result.Unmarshal(ctx, resp.Return); err != nil {
if strings.Contains(err.Error(), "got an asset") {
return fmt.Errorf("result struct field must be pulumi.Asset for asset-typed schema property: %w", err)
}
return err
} Prevention
- Type result/output struct fields as pulumi.Asset when the schema marks the property as an asset
- Regenerate provider SDKs after schema changes instead of hand-editing structs
- Check `pulumi schema` output to confirm property types before writing result structs
When it happens
Trigger: Declaring an output/result field of a non-asset type (string, pulumi.StringOutput, interface{}, custom struct) while the engine returns an Asset for that property - e.g. in a resource method's Check/Invoke-style outputs struct or a GetX result field typed wrongly.
Common situations: Mismatch between the Pulumi schema (which says a property is an asset) and a hand-written Go result struct; copying a result struct from another language SDK where the property was a plain string; schema drift after a provider upgrade changed the property to an AssetOrArchive.
Related errors
- unexpected asset hash of type %T
- unexpected asset text of type %T
- unexpected asset path of type %T
- unexpected asset URI of type %T
- expected a %s, got an asset
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/8c59fe88072ee9c0.
Report an issue: GitHub.