microsoft/aspire · error · AppHostUsageError
Argument ' ' passed to capability ' ' is a Promise-like…
Error message
Argument '${path}' passed to capability '${capabilityId}' is a Promise-like value. This usually means an async builder call was not awaited. Did you forget 'await' on a call like builder.addPostgres(...) or resource.addDatabase(...)? What it means
Before sending a capability invocation, validateValue walks the argument tree and rejects any Promise-like value. A Promise in the payload almost always means an async builder call (builder.addPostgres(...), resource.addDatabase(...)) was not awaited, so the pending promise — not the resource handle — was passed as an argument. The library fails fast with a targeted hint instead of sending garbage over the wire.
Solutions
- Add 'await' to the async builder call whose result is being passed: pass the resolved resource, not the Promise.
- If collecting multiple resources, await inside the callback or use Promise.all before consuming the values.
- Enable TypeScript's no-floating-promises lint rule to catch un-awaited calls at authoring time.
- Check the argument named in the error ('path') to find the exact un-awaited expression.
Example fix
// before
const app = builder.addApp("app", { db: builder.addPostgres("pg") }); // Promise passed
// after
const pg = await builder.addPostgres("pg");
const app = builder.addApp("app", { db: pg }); Defensive patterns
Strategy: validation
Validate before calling
function assertNoPromises(value: unknown, path = "arg", seen = new Set<object>()): void {
if (value === null || typeof value !== "object") return;
if (typeof (value as { then?: unknown }).then === "function") throw new TypeError(`'${path}' is an un-awaited Promise`);
if (seen.has(value)) return;
seen.add(value);
for (const [k, v] of Object.entries(value)) assertNoPromises(v, `${path}.${k}`, seen);
} Type guard
function isPromiseLike(v: unknown): v is PromiseLike<unknown> {
return v !== null && typeof v === "object" && typeof (v as { then?: unknown }).then === "function";
} Try / catch
try {
await capability(args);
} catch (e) {
if (e instanceof Error && e.message.includes("Promise-like value")) {
const m = e.message.match(/Argument '([^']+)'/);
throw new Error(`Un-awaited async call at '${m?.[1]}'; add await to the builder call producing that argument`, { cause: e });
}
throw e;
} Prevention
- Await every async builder call before using its result.
- Enable the @typescript-eslint/no-floating-promises lint rule.
- Inside map()/loops, await per item or collect with Promise.all before use.
- Check the 'path' in the error message to locate the exact offending argument.
When it happens
Trigger: Passing the direct return value of an async builder method into another capability call without await: addResource(pg.addDatabase("db")) where addDatabase is async; putting builder call results into arrays/objects passed as arguments; forgetting await inside map() callbacks.
Common situations: Migrating code from sync to async builder APIs; chaining calls across lines and missing one await; using Promise.all results incorrectly; new team members unfamiliar with which SDK calls are async.
Related errors
- AspireDict must be resolved before it can be serialized…
- AspireList must be resolved before it can be serialized…
- Cannot use null or undefined in reference expression
- Flushing pending promise(s). Consider awaiting fluent calls…
- The operation was aborted before it was sent to the AppHost.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/320351e363e1bea7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.mts:415
typeof (value as { then?: unknown }).then === 'function'
);
}
function validateCapabilityArgs(
capabilityId: string,
args?: Record<string, unknown>
): void {
if (!args) {
return;
}
const validateValue = (value: unknown, path: string, ancestors: Set<object>): void => {
if (value === null || value === undefined) {
return;
}
if (isPromiseLike(value)) {
throw new AppHostUsageError(
`Argument '${path}' passed to capability '${capabilityId}' is a Promise-like value. ` +
`This usually means an async builder call was not awaited. ` +
`Did you forget 'await' on a call like builder.addPostgres(...) or resource.addDatabase(...)?`
);
}
if (typeof value !== 'object') {
return;
}
if (ancestors.has(value)) {
throw createCircularReferenceError(capabilityId, path);
}
ancestors.add(value);
try {
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {View on GitHub (pinned to 25830f84bd)