pulumi/pulumi · error
malformed resource reference: packageVersion must be a strin
Error message
malformed resource reference: packageVersion must be a string
What it means
A resource-reference property value (ResourceReferenceSig) contains a "packageVersion" field that is not a JSON string. The deserializer requires it be a string semver and throws this error.
Source
Thrown at pkg/resource/stack/deployment.go:1117
plaintext, plainOk := objmap["plaintext"].(string)
if (!cipherOk && !plainOk) || (plainOk && cipherOk) {
return resource.PropertyValue{}, errors.New(
"malformed secret value: exactly one of `ciphertext` or `plaintext` must be supplied",
)
}
secret := &apitype.SecretV1{
Sig: resource.SecretSig,
Plaintext: plaintext,
Ciphertext: ciphertext,
}
return deserializeSecret(ctx, secret, dec)
case resource.ResourceReferenceSig:
var packageVersion string
if packageVersionV, ok := objmap["packageVersion"]; ok {
packageVersion, ok = packageVersionV.(string)
if !ok {
return resource.PropertyValue{},
errors.New("malformed resource reference: packageVersion must be a string")
}
}
urnStr, ok := objmap["urn"].(string)
if !ok {
return resource.PropertyValue{}, errors.New("malformed resource reference: missing urn")
}
urn := resource.URN(urnStr)
// deserializeID handles two cases, one of which arose from a bug in a refactoring of resource.ResourceReference.
// This bug caused the raw ID PropertyValue to be serialized as a map[string]any. In the normal case, the
// ID is serialized as a string.
deserializeID := func() (string, bool, error) {
idV, ok := objmap["id"]
if !ok {
return "", false, nil
}
View on GitHub (pinned to 793f7b2e16)
Solutions
- Change packageVersion to a string (e.g. "5.0.0") in the serialized property
- Remove packageVersion entirely if the version is unknown
- Regenerate the deployment/state via official Pulumi tooling
Example fix
// before
{"sig":"...", "urn":"...", "packageVersion": 5}
// after
{"sig":"...", "urn":"...", "packageVersion": "5.0.0"} Defensive patterns
Strategy: type-guard
Validate before calling
if pv, ok := objmap["packageVersion"]; ok {
if _, isStr := pv.(string); !isStr {
return errors.New("packageVersion must be a string")
}
} Type guard
func hasStringPackageVersion(m map[string]any) bool {
v, ok := m["packageVersion"]; if !ok { return true }; _, isStr := v.(string); return isStr
} Prevention
- Always JSON-quote version strings, including bare versions like "3"
- Use typed structs (apitype.ResourceReferenceV1) instead of raw maps when generating state
- Add schema validation to any tool that writes deployment documents
When it happens
Trigger: Deserializing a PropertyValue with resource-reference signature whose objmap["packageVersion"] is a number, object, or other non-string JSON value.
Common situations: JSON tooling writing numeric versions (e.g. 3 instead of "3.0.0"), hand-edited state, or buggy third-party generators of deployment documents.
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: id must be a string
- malformed resource reference: missing urn
- malformed byte string: missing or non-string 'value' field
- unexpected asset hash of type %T
- unexpected asset text of type %T
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/4f9f7098b08a342b.
Report an issue: GitHub.