pulumi/pulumi · warning · Error
${leakMessage}
Error message
${leakMessage} What it means
After the Pulumi CLI process exits, the language server checks debuggable.leakedPromises() for promises that were never awaited. If the program exited cleanly but promises leaked (indicating work that silently never completed), the server throws with a diagnostic message describing the leaks. This is suppressed when the program already errored to keep output clean.
Source
Thrown at sdk/nodejs/automation/server.ts:46
* @internal
*/
export class LanguageServer<T> implements grpc.UntypedServiceImplementation {
readonly program: () => Promise<T>;
// Satisfy the grpc.UntypedServiceImplementation interface.
[name: string]: any;
constructor(program: () => Promise<T>) {
this.program = program;
}
onPulumiExit(hasError: boolean) {
// Check for leaks once the CLI exits but skip if the program otherwise
// errored to keep error output clean
if (!hasError) {
const [leaks, leakMessage] = debuggable.leakedPromises();
if (leaks.size !== 0) {
throw new Error(leakMessage);
}
}
}
getRequiredPlugins(call: any, callback: any): void {
const resp: any = new langproto.GetRequiredPluginsResponse();
resp.setPluginsList([]);
callback(undefined, resp);
}
run(call: any, callback: any): Promise<void> {
const req: any = call.request;
const resp: any = new langproto.RunResponse();
// Setup a new async state store for this run
return localState.withLocalStorage(async () => {
const errorSet = new Set<Error>();
const uncaughtHandler = newUncaughtHandler(errorSet);View on GitHub (pinned to 793f7b2e16)
Solutions
- Await every promise created in the program, especially inside apply callbacks.
- Check the leakMessage for the stack trace identifying the un-awaited call site.
- Enable promise-leak debugging by following the message's pointer to where the promise was created.
Example fix
// before
bucket.onObjectCreated('handler', handler); // returns promise, not awaited
// after
const done = bucket.onObjectCreated('handler', handler);
await done; // or ensure it resolves before program end Defensive patterns
Strategy: try-catch
Validate before calling
process.on('unhandledRejection', (r) => console.error('leaked promise:', r)); Try / catch
try { await program(); } catch (e) { if (String(e.message).includes('leaked')) { console.error(e.message); process.exitCode = 1; } else throw e; } Prevention
- Await every async call in the Pulumi program
- Enable strict mode and no-floating-promises ESLint rule
- Run with --stack-trace-limit high enough to see leak origins
When it happens
Trigger: A Node.js Pulumi program registers a promise (e.g. an un-awaited async call or .then chain) that is still pending/unhandled when the program finishes; onPulumiExit then throws with the leak report.
Common situations: Forgetting to await an output.apply side effect or an async function call in the program; fire-and-forget operations like exports of unresolved values.
Related errors
- failed to run tsc: %w
- copy package.json: %w
- expected entrypoint module to have either a default export o
- Calling [toJSON] on an [Output<T>] is not supported. To get
- Component '${componentName}' must have exactly one construct
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/077220c6882dff7f.
Report an issue: GitHub.