Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Pulumi By James Joyner IV · · 8 min read Last reviewed Jul 2026

Pulumi Error: Error Thrown Inside a ComponentResource Constructor

Quick answer

Fix Pulumi 'exception in ComponentResource constructor' and missing registerOutputs errors: diagnose thrown constructor code, super() ordering, and unresolved child outputs.

  • #pulumi
  • #iac
  • #troubleshooting
  • #errors
Free toolkit

Stuck on this Pulumi error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Exact Error Message

error: Running program '/home/ci/app' failed with an unhandled exception:
    <ref *1> Error: Cannot read properties of undefined (reading 'id')
        at new MyService (/home/ci/app/service.ts:24:41)
        at Object.<anonymous> (/home/ci/app/index.ts:6:17)

error: an unhandled error occurred: Program exited with non-zero exit code: 1

You may also see the resource stuck reporting registerResourceOutputs never completing, or a warning such as Component resource was not registered; did you call registerOutputs? when a ComponentResource subclass throws before it finishes wiring up its children.

What It Means

A ComponentResource is a logical container you build in your program’s language (TypeScript, Python, Go, .NET). Pulumi calls your subclass constructor to create the child resources, then expects you to publish the component’s outputs with this.registerOutputs(...). If any line inside that constructor throws, the whole pulumi up/pulumi preview aborts with an unhandled exception, because your program crashed before the engine could finish registering the component tree.

This is application code failing, not the Pulumi engine or a cloud provider rejecting a request. The stack trace points at your file and line, so the fix is almost always in the constructor body: an undefined value, a missing parent option, or a registerOutputs call that never runs.

Common Causes

  • Dereferencing a value that is still an Output<T> (or Awaitable) as if it were a plain string, e.g. reading bucket.id synchronously.
  • The constructor throws before reaching this.registerOutputs({...}), leaving the component half-built.
  • Forgetting to call super("pkg:module:MyService", name, {}, opts) first, so this is not initialized when you create children.
  • Child resources not passed { parent: this }, causing them to register outside the component and orphaning outputs.
  • A synchronous exception (bad config lookup, null map access, failed require) inside the constructor.

Diagnostic Commands

Re-run with full detail to see the exact throwing line and stack:

pulumi up --logtostderr --logflow -v=9 2>pulumi.log

Preview only, so you can iterate without mutating cloud state:

pulumi preview --diff

Confirm which stack and config the program is reading (bad config often triggers the throw):

pulumi stack --show-name
pulumi config

For TypeScript programs, type-check the constructor independently of Pulumi:

npx tsc --noEmit

Step-by-Step Resolution

  1. Read the stack trace top-down and open the file:line it names. The first frame inside your code is the real culprit, not the Pulumi library frames beneath it.

  2. Call super() as the very first statement, before creating any children:

export class MyService extends pulumi.ComponentResource {
  constructor(name: string, args: MyServiceArgs, opts?: pulumi.ComponentResourceOptions) {
    super("myorg:app:MyService", name, {}, opts);
    // create children AFTER super()
  }
}
  1. Parent every child to the component so its outputs register correctly:
const bucket = new aws.s3.Bucket(`${name}-bucket`, {}, { parent: this });
  1. Never treat an Output<T> as a raw value inside the constructor. Chain with .apply() instead of reading it directly:
this.url = bucket.bucketRegionalDomainName.apply(d => `https://${d}`);
  1. Always finish the constructor with registerOutputs, even if empty, so the engine knows the component is complete:
    this.registerOutputs({ url: this.url });
  }
}
  1. Re-run and confirm the component and its children appear in the plan:
pulumi preview --diff
+ myorg:app:MyService  my-service  create
+ └─ aws:s3:Bucket     my-service-bucket  create

Prevention

  • Put super(...) first and this.registerOutputs(...) last in every ComponentResource constructor as a fixed template.
  • Keep constructor logic pure: no top-level await on cloud calls, no synchronous reads of Output<T>.
  • Pass { parent: this } to every child resource so the component tree is coherent.
  • Run tsc --noEmit (or the equivalent build for Go/.NET/Python type checks) in CI before pulumi preview.
  • Validate and default your args at the top of the constructor so a missing field fails with a clear message, not a deep undefined.
  • Reach for ready-made component scaffolding from the Pulumi prompt library to get the super/registerOutputs boilerplate right the first time.
  • resource registration ... timed out — a hang, not a thrown exception, usually a blocked async call.
  • Component resource was not registered; did you call registerOutputs? — the constructor returned without registering outputs.
  • TypeError: Cannot read properties of undefined — the most common underlying throw inside a constructor.
  • unknown resource type — a child resource whose provider plugin is not installed.

Frequently Asked Questions

Why does my whole pulumi up fail when only one component throws? Because your program runs as a single process; an unhandled exception anywhere aborts the process before the engine can complete the deployment, so nothing after the throw is applied.

Do I have to call registerOutputs if my component has no outputs? Yes, call this.registerOutputs({}). It signals to the engine that the component is fully constructed; skipping it can leave the component in a partially registered state.

Why is bucket.id undefined inside my constructor? During preview, resource IDs are unknown, and even at update time id is an Output<T>, not a string. Use .apply() or pulumi.interpolate instead of reading it synchronously.

Does parent: this really matter? Yes. Without it, child resources register outside the component, so the component’s dependency graph and outputs are wrong even if the program does not throw.

Where do I set the component options like providers or protect? Pass them through the opts argument to super(); they propagate to children that use { parent: this }. For more component and provider patterns, see the Pulumi guides.

Free download · 368-page PDF

Fixed it? Get 500 Pulumi & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.