pulumi/pulumi · error
malformed resource reference for %q: id not a string
Error message
malformed resource reference for %q: id not a string
What it means
In a resource reference, the 'id' field may be a plain string, a computed (unknown) value, or a known output wrapping a string. This error fires in the default branch of the ID switch: the ID was present but its property type is none of those accepted shapes (e.g. a number, bool, object, secret, or unknown output), so the deserializer cannot extract a resource ID string.
Source
Thrown at sdk/go/common/resource/plugin/rpc.go:529
if typeProp, ok := obj["type"]; ok {
if !typeProp.IsString() {
return nil, fmt.Errorf("malformed resource reference for %q: type not a string", key)
}
typ = typeProp.StringValue()
}
id, hasID := "", false
if idProp, ok := obj["id"]; ok {
hasID = true
switch {
case idProp.IsString():
id = idProp.StringValue()
case idProp.IsComputed():
// Leave the ID empty to indicate that it is unknown.
case idProp.IsOutput():
if idProp.OutputValue().Known {
if !idProp.OutputValue().Element.IsString() {
return nil, fmt.Errorf("malformed resource reference for %q: id not a string", key)
}
id = idProp.OutputValue().Element.StringValue()
}
default:
return nil, fmt.Errorf("malformed resource reference for %q: id not a string", key)
}
}
var packageVersion string
if packageVersionProp, ok := obj["packageVersion"]; ok {
if !packageVersionProp.IsString() {
return nil, fmt.Errorf("malformed resource reference for %q: packageVersion not a string", key)
}
packageVersion = packageVersionProp.StringValue()
}
if !opts.KeepResources {
value := urn.StringValue()View on GitHub (pinned to 793f7b2e16)
Solutions
- Convert the resource ID to a string before serialization (e.g. strconv.FormatInt for numeric IDs).
- If the ID is unknown, serialize it as an unknown/computed value rather than a concrete non-string.
- If wrapped as a secret, use a secret-wrapped string so the element remains a string.
- Fix or remove the malformed id in exported state, then pulumi stack import.
Example fix
// before (producer)
m["id"] = resource.NewProperty(int64(12345))
// after
m["id"] = resource.NewProperty("12345") Defensive patterns
Strategy: type-guard
Validate before calling
func validIDProp(p resource.Property) bool {
return p.IsString() || p.IsComputed() ||
(p.IsOutput() && (!p.OutputValue().Known || p.OutputValue().Element.IsString()))
} Type guard
func asResourceID(p resource.Property) (string, bool) {
switch {
case p.IsString():
return p.StringValue(), true
case p.IsOutput() && p.OutputValue().Known && p.OutputValue().Element.IsString():
return p.OutputValue().Element.StringValue(), true
default:
return "", false
}
} Prevention
- Convert numeric IDs to strings before serialization (strconv.FormatInt etc.).
- Represent unknown IDs as computed/unknown values, not concrete non-strings.
- Wrap secret IDs as secret strings so the underlying element stays a string.
- Round-trip test provider serialization with the engine's deserializer in CI.
When it happens
Trigger: obj["id"] is a non-string, non-computed, non-output property (number, bool, object, secret wrapper); a provider serializes an unknown ID as something other than a computed/unknown output.
Common situations: Custom providers storing numeric IDs (common in AWS-like providers) without converting to string; hand-edited state; serializers that wrap IDs in secrets; SDK version skew on how unknown IDs are represented.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- malformed resource reference for %q: missing urn
- malformed resource reference for %q: name not a string
- malformed resource reference for %q: type not a string
- malformed resource reference for %q: packageVersion not a st
- failed to serialize snapshot: %w
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/21bfb877fb45ec3c.
Report an issue: GitHub.