Skip to content

Fix awsx:ecr:Image refresh crash after 2.19 upgrade - #1943

Merged
corymhall merged 2 commits into
masterfrom
triage-1926
Apr 15, 2026
Merged

Fix awsx:ecr:Image refresh crash after 2.19 upgrade#1943
corymhall merged 2 commits into
masterfrom
triage-1926

Conversation

@corymhall

@corymhall corymhall commented Apr 14, 2026

Copy link
Copy Markdown
Member

Summary

  • fix the awsx.ecr.Image refresh crash when upgrading stacks from awsx 2.19.0
  • persist imageUri on the component and avoid rebuilding child resources during component rehydration
  • add an upgrade repro that covers 2.19.0 -> current with both refresh --run-program and up --refresh --run-program

Motivation

This PR fixes the scenario reported in #1926.

The issue only shows up on an upgrade path. Fresh awsx 3.x stacks do not reproduce it.

The relevant sequence is:

  1. A stack is originally deployed with awsx 2.19.0.
  2. awsx.ecr.Image creates a docker:index/image:Image child resource.
  3. That old child stores repoDigest, and the component returns a digest-form image URI like:
    repo@sha256:...
  4. The stack is later upgraded to current awsx.
  5. The user runs pulumi refresh --run-program.

At that point, the new implementation expects the docker-build:index:Image world (digest / ref), but the old stack still contains the legacy docker:index/image:Image child.

What Was Happening

There are really two separate issues here:

1. Refresh crash on upgrade from 2.19.0

Current awsx.ecr.Image derives its output from docker-build.Image.ref.

On the 2.19.0 -> current upgrade path during refresh --run-program, the child resource has not yet been migrated to docker-build:index:Image, so there is no usable ref from the new child shape.

That led to:

  • image.ref being undefined
  • removeTagFromRef(image.ref) throwing
  • refresh failing

2. Missing persisted component output

Older awsx.ecr.Image did not call registerOutputs, so the component’s own imageUri output was not persisted in checkpoint state.

That means that on upgrade, the engine cannot rehydrate a previously stored imageUri for the component itself and instead has to recompute it from current program behavior.

Important Behavior We Verified

Fresh current-version stacks are fine

A fresh stack using current awsx does not reproduce this issue.

2.20.0 -> current is also fine

awsx 2.20.0 had already switched to docker-build:index:Image, so those stacks already have digest / ref state and refresh behaves normally.

The problematic path is specifically 2.19.0 -> current

That is the version boundary where the child resource implementation changed from:

  • docker:index/image:Image
    to:
  • docker-build:index:Image

refresh --run-program and up --refresh --run-program behave differently

For stacks originating on 2.19.0:

  • refresh --run-program does not complete the child-resource migration
  • up --refresh --run-program does replace the old child with the new docker-build:index:Image

So the crash happens on refresh, but a full update is able to converge the stack.

Root Cause

The root cause is the combination of:

  • a resource type migration from docker.Image to docker-build.Image
  • old 2.19.0 state containing repoDigest rather than digest / ref
  • awsx.ecr.Image assuming ref exists in the new world
  • the component not having previously persisted its own imageUri

Fix

This PR takes the narrow, safe fix:

  1. If the component is being rehydrated (opts.urn), do not reconstruct child resources.
  2. Call registerOutputs({ imageUri }) so the component output is persisted going forward.
  3. When deriving imageUri from docker-build.Image, prefer:
    • digest
    • then ref
    • then a final fallback to the canonical tag form

This is enough to eliminate the refresh crash and make the stack converge correctly on the subsequent update path.

Behavioral Note

This PR is intentionally scoped to removing the refresh error.

For stacks that originated on awsx 2.19.0, a refresh --run-program can still temporarily rewrite the component output from digest form to tag form until a later:

pulumi up --refresh --run-program

completes the child-resource migration to docker-build:index:Image.

That behavior already self-heals once the update runs; this PR ensures refresh no longer crashes on the way there.

Testing

Unit

  • yarn --cwd awsx test ecr/image.test.ts --runInBand
  • yarn --cwd awsx tsc --noEmit

Repro coverage

Added a targeted upgrade repro that exercises:

  • baseline deploy with awsx 2.19.0
  • upgrade to current local provider
  • pulumi refresh --run-program
  • pulumi up --refresh --run-program

fixes #1926

@github-actions

Copy link
Copy Markdown
Contributor

Does the PR have any schema changes?

Looking good! No breaking changes found.
No new resources/functions.

Maintainer note: consult the runbook for dealing with any breaking changes.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed for bugs and CLAUDE.md compliance. No actionable issues found.

The core fix is correct: the opts.urn guard is an established Pulumi component rehydration pattern, registerOutputs is correctly placed on the non-rehydration path so imageUri is persisted for future refreshes, and the three-tier URI fallback (digestrefcanonicalImageName) is explicitly documented and intentionally scoped in the PR description. No generated files were modified. Tests cover the crash scenario.

Reviewed by Internal Trusted PR Reviewer

To install this agentic workflow, run

gh aw add pulumi-labs/gh-aw-internal/.github/workflows/gh-aw-pr-review.md@9a981e07d7134a447fac35073f0857f8512f16c4

@corymhall
corymhall requested a review from a team April 15, 2026 09:21
const repository = new awsx.ecr.Repository("repository", { forceDelete: true });

export const repositoryName = repository.repository.name;
export const image = new awsx.ecr.Image("image", {

@pose pose Apr 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@corymhall Could this Pulumi program be made into a YAML program or since the component code is in TS it would be problematic?

@pose pose left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making the test a YAML test @corymhall

@corymhall
corymhall enabled auto-merge (squash) April 15, 2026 16:49
@corymhall
corymhall merged commit 92d68a6 into master Apr 15, 2026
21 checks passed
@corymhall
corymhall deleted the triage-1926 branch April 15, 2026 17:21
@pulumi-bot

Copy link
Copy Markdown
Contributor

This PR has been shipped in release v3.6.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

awsx:ecr:Image: pulumi refresh fails with Cannot read properties of undefined (reading 'replace')

3 participants