{"record":{"id":"320351e363e1bea7","repo":"microsoft/aspire","slug":"argument-path-passed-to-capability-capabilityid-is-a-promise","errorCode":null,"errorMessage":"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(...)?","messagePattern":"Argument '(.+?)' passed to capability '(.+?)' 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\\(\\.\\.\\.\\)\\?","errorType":"exception","errorClass":"AppHostUsageError","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.mts","lineNumber":415,"sourceCode":"        typeof (value as { then?: unknown }).then === 'function'\n    );\n}\n\nfunction validateCapabilityArgs(\n    capabilityId: string,\n    args?: Record<string, unknown>\n): void {\n    if (!args) {\n        return;\n    }\n\n    const validateValue = (value: unknown, path: string, ancestors: Set<object>): void => {\n        if (value === null || value === undefined) {\n            return;\n        }\n\n        if (isPromiseLike(value)) {\n            throw new AppHostUsageError(\n                `Argument '${path}' passed to capability '${capabilityId}' is a Promise-like value. ` +\n                `This usually means an async builder call was not awaited. ` +\n                `Did you forget 'await' on a call like builder.addPostgres(...) or resource.addDatabase(...)?`\n            );\n        }\n\n        if (typeof value !== 'object') {\n            return;\n        }\n\n        if (ancestors.has(value)) {\n            throw createCircularReferenceError(capabilityId, path);\n        }\n\n        ancestors.add(value);\n        try {\n            if (Array.isArray(value)) {\n                for (let i = 0; i < value.length; i++) {","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.mts#L397-L433","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst app = builder.addApp(\"app\", { db: builder.addPostgres(\"pg\") }); // Promise passed\n\n// after\nconst pg = await builder.addPostgres(\"pg\");\nconst app = builder.addApp(\"app\", { db: pg });","handlingStrategy":"validation","validationCode":"function assertNoPromises(value: unknown, path = \"arg\", seen = new Set<object>()): void {\n  if (value === null || typeof value !== \"object\") return;\n  if (typeof (value as { then?: unknown }).then === \"function\") throw new TypeError(`'${path}' is an un-awaited Promise`);\n  if (seen.has(value)) return;\n  seen.add(value);\n  for (const [k, v] of Object.entries(value)) assertNoPromises(v, `${path}.${k}`, seen);\n}","typeGuard":"function isPromiseLike(v: unknown): v is PromiseLike<unknown> {\n  return v !== null && typeof v === \"object\" && typeof (v as { then?: unknown }).then === \"function\";\n}","tryCatchPattern":"try {\n  await capability(args);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"Promise-like value\")) {\n    const m = e.message.match(/Argument '([^']+)'/);\n    throw new Error(`Un-awaited async call at '${m?.[1]}'; add await to the builder call producing that argument`, { cause: e });\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["async","typescript","unawaited-promise","validation"],"backgroundTag":"unawaited-promise","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}