microsoft/aspire · error · Error
Cannot use value of type
Error message
Cannot use value of type ${typeof value} in reference expression. Expected a Handle, string, or number. What it means
extractHandleForExpr builds a reference expression ($handle/$expr JSON) from a value passed where a resource reference is expected. It only accepts Handle objects, strings, and numbers; anything else (object, boolean, array, undefined) is rejected. This guards the wire protocol so only marshallable reference values reach the app host.
Solutions
- Pass the awaited Handle (or a string/number) instead of a raw object: const db = await resource.addDatabase(...); then pass db.
- Add 'await' to async builder calls so the argument is the resolved value, not a Promise.
- Check the generated SDK signature for the parameter to confirm which types are accepted.
- If passing dynamic data, wrap it as a parameter/expr through the supported APIs rather than a reference argument.
Example fix
// before
const db = resource.addDatabase("mydb"); // not awaited
builder.withReference(someOptionsObject); // object not a Handle
// after
const db = await resource.addDatabase("mydb");
builder.withReference(db); // Handle is accepted Defensive patterns
Strategy: type-guard
Validate before calling
function isReferenceValue(v: unknown): boolean {
return typeof v === "string" || typeof v === "number" || (v !== null && typeof v === "object" && "$handle" in (v as object));
}
if (!isReferenceValue(arg)) throw new TypeError("Reference argument must be a Handle, string, or number"); Type guard
function isHandleLike(v: unknown): v is Handle {
return v !== null && typeof v === "object" && "$handle" in v;
} Try / catch
try {
builder.withReference(arg);
} catch (e) {
if (e instanceof Error && e.message.includes("reference expression")) {
throw new Error(`Argument is not a Handle/string/number; did you forget await? Got: ${typeof arg}`, { cause: e });
}
throw e;
} Prevention
- Always await async builder calls before passing their results.
- Type parameters as Handle | string | number so the compiler rejects bad values.
- Never pass config objects into reference-typed arguments.
When it happens
Trigger: Passing a non-primitive, non-Handle value into generated SDK builder methods that expect a reference: e.g. resource.addDatabase({ param: someObject }), passing a plain JS object or boolean where a Handle/string/number is required, or forgetting to await an async call so the argument is a Promise rather than the Handle.
Common situations: Copy-pasting config objects into reference slots; calling an async builder (addPostgres, addDatabase) without await and passing the pending result; passing undefined because an earlier call returned nothing; TypeScript loosened to unknown/any losing the Handle type.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot use null or undefined in reference expression
- getValue is only available on server-returned…
- A of type cannot be assigned to a BicepValue< >.
- Argument ' ' passed to capability ' ' contains a circular…
- Argument ' ' passed to capability ' ' is a Promise-like…
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/a5ca9a36e7e1c200.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/base.mts:292
// Handle objects - get their JSON representation
if (isHandleLike(value)) {
return value.toJSON();
}
// Objects with marshalled expression/handle payloads
if (typeof value === 'object' && value !== null && ('$handle' in value || '$expr' in value)) {
return value;
}
// Objects with toJSON that returns a marshalled expression or handle
if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') {
const json = value.toJSON();
if (json && typeof json === 'object' && ('$handle' in json || '$expr' in json)) {
return json;
}
}
throw new Error(
`Cannot use value of type ${typeof value} in reference expression. ` +
`Expected a Handle, string, or number.`
);
}
function isHandleLike(value: unknown): value is Handle {
return (
value !== null &&
typeof value === 'object' &&
'$handle' in value &&
typeof (value as { $handle?: unknown }).$handle === 'string' &&
'$type' in value &&
typeof (value as { $type?: unknown }).$type === 'string' &&
'toJSON' in value &&
typeof (value as { toJSON?: unknown }).toJSON === 'function'
);
}
View on GitHub (pinned to 25830f84bd)