Generated banner for Pulumi Upgrade Provider
Generated logo for Pulumi Upgrade Provider

Pulumi Upgrade Provider

PulumiOfficialPublished by Pulumi

  • Skill
  • Workflow
  • Cloud and DevOps
  • Apache-2.0
  • No issues found

From the author

Automate Pulumi provider repo upgrades with the `upgrade-provider` tool. Use when upgrading a pulumi provider repository to a new upstream version, running `upgrade-provider`, and addressing its common failure modes like patch conflicts or missing module mappings.
— the description by Pulumi

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured workflow for upgrading Pulumi provider repositories to new upstream versions. It guides the user through running the upgrade-provider tool in a non-submitting mode, managing the repository state, resolving common errors such as patch conflicts or module mapping issues, and performing a final review before submission. The process ensures that generated code and documentation are correctly updated while maintaining the integrity of the provider's history and configuration.

What it does

  • Executes the upgrade-provider tool to automate repository updates.
  • Provides a systematic loop for identifying and fixing upgrade failures.
  • Offers guidance on resolving patch conflicts and upstream dependency issues.
  • Includes steps for auditing generated documentation for placeholders.
  • Defines a review process for verifying changes before final submission.
  • Outlines the procedure for submitting the upgrade via pull requests.

When to use it

  • When a Pulumi provider needs to be upgraded to a new upstream version.
  • When the upgrade-provider tool encounters errors during the automated process.
  • When manual intervention is required to resolve patch conflicts or module mapping issues.
  • When verifying the generated output of an upgrade before pushing changes.

Advantages

  • Standardizes the upgrade process across different provider repositories.
  • Provides clear error resolution paths for common upgrade blockers.
  • Ensures that generated commits and documentation are reviewed for accuracy.
  • Maintains a clean and reproducible workflow for provider maintenance.

Usage examples

“Upgrade the current provider repository to the latest upstream version.”
The agent initiates the upgrade-provider tool with the --no-submit flag, monitors the logs for errors, and provides a report on the local completion status.
“I encountered a patch conflict while running the provider upgrade. How do I fix it?”
The agent directs you to resolve the conflict within the upstream submodule, verify the patch intent, and use the check_in script before rerunning the upgrade.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/pulumi/pulumi-upgrade-provider/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip pulumi-upgrade-provider.zip -d .agents/skills

Documentation by Pulumi

Pulumi Upgrade Provider

Overview

Run upgrade-provider --no-submit, fix known failures, and rerun until success. During the run loop, the tool owns branch and generated-commit state but does not push or mutate GitHub. After success, review and correct the local result before submitting it using the plan printed by the tool.

Preflight

  1. Record existing changes as the pre-upgrade baseline:

baseline_file="${TMPDIR:-/tmp}/upgrade-provider-$(basename "$PWD")-baseline.txt"
git status --short --untracked-files=all | tee "$baseline_file"

Existing changes do not block the upgrade, but the tool stages broadly and may include them in generated commits. If practical, isolate clearly unrelated work in another branch or worktree, move local-only files, or add untracked local artifacts to .git/info/exclude. Otherwise proceed and carry this baseline into the final review. Do not add a repository .gitignore rule unless the path should be ignored for all contributors.

  1. Keep the run log outside the repository so the tool cannot stage it.

Run Loop

  1. Run from repo root:

log_file="${TMPDIR:-/tmp}/upgrade-provider-$(basename "$PWD").log"
upgrade-provider $ORG/$REPO --repo-path . --no-submit > "$log_file" 2> /dev/null

Preserve --no-submit on every retry.

  1. Wait for completion (can take up to 10 minutes).

  2. Check for errors by scanning the log for lines starting with error: :

if command -v rg >/dev/null 2>&1; then
  rg -n '^error: ' "$log_file" || true
else
  grep -n '^error: ' "$log_file" || true
fi
  1. On a successful exit, first check whether the tool found that no upgrade was required:

if grep -Fq 'No actions needed' "$log_file"; then
  echo 'No actions needed'
fi

If present, report that the provider is already current or the requested target is not an upgrade, then stop successfully. There is no local upgrade to review or submit.

  1. Otherwise, extract and read the complete local-completion report from the captured stdout:

awk '/^Upgrade completed locally;/{found=1} found' "$log_file"

This includes the proposed PR body and metadata, review commands, and every skipped submission action.

  1. If failed, fix using this skill's references/upgrade-provider-errors.md (from the skill folder, not the repo), then rerun with --no-submit. If upstream migrated from Terraform Plugin SDKv2 to Plugin Framework, use the migration-guide routing in that reference instead of treating the framework change alone as an architectural blocker. For upstream go get failures involving ignored replace directives or unknown revision v0.0.0, rerun with --target-version after applying the documented provider/go.mod replacements; preserve the original major/non-major intent and add --major only for actual major version upgrades.

  2. If a fix requires creating/amending/removing/rebasing patches, use the upstream-patches skill for the patch workflow. Interrupted patch workflows must be checked in before rerunning.

  3. If you fixed a conflict, report exact edits (file paths + concrete changes or preserved intent).

  4. Repeat until the tool prints No actions needed or the local-completion report and proposed PR plan. This run must not push or mutate GitHub; a branch or PR from an earlier run may already exist.

When to Stop and Report Failure

Stop iterating and report failure if any of these conditions are met:

  1. Command not found (exit code 127): The upgrade-provider tool is not in PATH.

  2. Same error 3 times: You've attempted to fix the same error 3 times without success.

  3. Unknown error pattern: The error is not covered in references/upgrade-provider-errors.md and you cannot determine a safe fix.

  4. Ambiguous patch state: You cannot prove that every patch was applied and the target rebase completed.

  5. Requires human judgment: The fix needs user input, such as choosing between multiple valid implementation approaches or making an architectural decision about module organization. Upstream breaking changes, deprecations, or framework migrations do not by themselves require stopping; stop only when implementing the upgrade presents an unresolved choice.

When stopping, report:

  1. The error(s) encountered.

  2. What fixes were attempted (with file paths and changes).

  3. Why human intervention is needed.

  4. Any partial progress.

Review the Local Upgrade

Use the tool's final report as the source of truth for the base branch, working branch, proposed PR title/body/metadata, and skipped submission actions.

  1. Review a bounded summary first:

default_branch=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name)
base_ref="origin/$default_branch"
git status --short --untracked-files=all
git log --oneline "$base_ref"..HEAD
git diff --shortstat "$base_ref"...HEAD
git diff --name-only "$base_ref"...HEAD | awk -F/ '{print $1}' | sort | uniq -c

Provider upgrades can change thousands of generated SDK files. Do not print the full branch diff by default. Use path-limited git diff "$base_ref"...HEAD -- <paths> commands to inspect source, configuration, patch, schema, and unexpected directories. For generated SDKs, inspect summaries or targeted files unless a full diff is necessary.

Cross-check the final branch against the pre-upgrade baseline:

baseline_file="${TMPDIR:-/tmp}/upgrade-provider-$(basename "$PWD")-baseline.txt"
[ ! -f "$baseline_file" ] || cat "$baseline_file"

For every pre-existing path included in the branch, decide whether it belongs in the upgrade PR. Keep intentional paths; move unrelated work to another branch/worktree or remove it from the unpublished upgrade history before pushing. A separate commit on the same branch isolates history but does not remove the path from the PR, and unstaging alone is insufficient after the tool has committed it. Revoke any exposed credential even if the history is rewritten.

  1. MUST audit generated doc replacements for unresolved placeholders before publication:

if [ -f provider/replacements.json ]; then
  if command -v rg >/dev/null 2>&1; then
    rg -n '"new":.*TODO|TODO' provider/replacements.json || true
  else
    grep -En '"new":.*TODO|TODO' provider/replacements.json || true
  fi
fi

If any TODO is found in provider/replacements.json:

  • Treat it as a pre-submission blocker; replacement values render into generated docs.

  • Inspect each old/new pair and replace TODO with concrete Pulumi-facing wording, usually Pulumi, this provider, or the provider.

  • Run focused validation if the repo has the test:

cd provider && go test -v -run TestReplacementDoesNotIncludeTodos .
  1. If the upgrade changed patches, review the applied commits and then exit checkout mode:

./scripts/upstream.sh checkout
git -C upstream log --oneline pulumi/checkout-base..pulumi/patch-checkout
# Inspect relevant commits with git -C upstream show <sha>.
./scripts/upstream.sh check_in

List commit SHAs/titles, summarize each intent, and call out behavioral changes or risks. check_in is mandatory after review; leaving upstream on pulumi/patch-checkout blocks the next safe tool run.

  1. Run focused validation for every manual fix and add focused follow-up commits.

  2. Require a clean working tree before submission.

Submit the Reviewed Upgrade

The local-completion report lists the proposed PR metadata and every skipped action. MUST reproduce all applicable actions, not only PR creation:

  1. Preserve the proposed title, body, release label, reviewers, and assignee. Never decide, infer, or change the release label: provider upgrades follow the upstream version transition, so the label represents that version delta rather than the agent's assessment of whether individual changes are breaking. For example, upstream v0.9.0 to v0.10.0 remains a minor upgrade even when it contains breaking behavioral changes. Use exactly the label emitted by upgrade-provider, report any concern to reviewers without changing the metadata, and never add --major unless the upstream target crosses the current upstream major version.

  2. If fixes unblocked the upgrade, append this section to the proposed body before submission when practical:

---

### Fixes applied to unblock upgrade

- <list concrete unblocker edits here, with file paths and intent>
  1. Push only after review. The tool reports an unconditional force-push; manual submission intentionally uses the safer lease-protected equivalent unless the user explicitly approves overwriting newer remote work:

branch=$(git branch --show-current)
git push --set-upstream origin "$branch" --force-with-lease
  1. Use gh to create or update the PR as described by the report.

  2. Assign listed upgrade issues to the PR assignee when requested.

  3. For bridge upgrades, close listed superseded bridge PRs and comment with the replacement PR URL.

  4. Fetch and report the final PR URL:

gh pr view --json url --jq .url || gh pr list --head "$(git branch --show-current)" --json url --jq '.[0].url'

If the fixes section was not included before submission, append it without replacing the existing body:

repo=$(gh repo view --json nameWithOwner --jq .nameWithOwner)
pr_number=$(gh pr view --json number --jq .number)
gh pr view --json body --jq .body > /tmp/pr_body.txt

cat <<'EOF' >> /tmp/pr_body.txt

---

### Fixes applied to unblock upgrade

- <list concrete unblocker edits here, with file paths and intent>
EOF

gh api -X PATCH "repos/$repo/pulls/$pr_number" --raw-field body="$(cat /tmp/pr_body.txt)"

Use REST (gh api) instead of gh pr edit to avoid GraphQL project-card errors. Keep existing body content; only append.

Notes

  • git rebase --continue --no-edit is not supported in older git versions. Use git rebase --continue and accept the existing commit message.

  • To avoid the editor prompt during git rebase --continue, run it with GIT_EDITOR=true (or GIT_EDITOR=:).

Guardrails

  • Never commit, push, or create branches manually during the upgrade-provider run loop.

  • After --no-submit succeeds, focused correction commits and manual submission are permitted.

  • Never use ./scripts/upstream.sh init -f unless intentionally discarding interrupted patch work; it is destructive.

  • Do not leave upstream in checkout or an active Git operation before submission.

  • Do not stash changes; use a clean worktree or remove unrelated artifacts instead.

References

  • Use this skill's references/upgrade-provider-errors.md (from the skill folder, not the repo) for interrupted patch state, patch conflict, SDKv2-to-Plugin-Framework migration, ignored upstream replacement, vendored upstream dependency, .NET duplicate file, and new module mapping fixes.

Files

references/upgrade-provider-errors.md

Upgrade Provider Errors

Use this file when the upgrade-provider tool fails and you need concrete fixes. For patch edits/removals/rebases, follow the upstream-patches skill workflow. Preserve --no-submit on every upgrade-provider retry.

Patched upstream has interrupted or unexpected Git state

The tool deliberately leaves active Git operations, pulumi/patch-checkout, and unexpected branches unchanged because it cannot prove that an interrupted checkout applied the complete patch stack.

Preserve work by default:

  1. Inspect git -C upstream status and identify whether git am, rebase, merge, cherry-pick, or another operation is active.

  2. Use skill upstream-patches for conflict resolution or patch edits.

  3. Complete or safely abort the active operation. If checkout was interrupted during git am, verify that every patches/*.patch was applied; later patch files may not have been reached.

  4. Ensure the patch stack was rebased onto the requested target. If needed, run the target rebase from the provider root and resolve it fully:

./scripts/upstream.sh rebase -o refs/tags/v<TARGET>
  1. Once every patch is applied and the target rebase is complete, write patches back and exit checkout mode:

./scripts/upstream.sh check_in
  1. Confirm upstream is no longer on pulumi/patch-checkout, then rerun upgrade-provider with --no-submit.

Only when intentionally discarding all interrupted patch work may you run:

./scripts/upstream.sh init -f

This deletes active operation state and patch-checkout work and can clean untracked files. Treat it as destructive discard, not normal recovery.

Patch conflicts during rebase

The tool uses scripts/upstream.sh to apply patch commits in the upstream submodule. If a patch no longer applies cleanly, you will see rebase errors like:

error: could not apply 83b04967e... docs patching
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".

Fix from the upstream directory, following upstream-patches defaults (edit the owning patch commit; do not create a new patch unless asked):

  1. Identify conflicted files.

  2. Resolve conflicts while preserving the intent of the patch in patches/.

  3. Search for conflict markers and remove all of them before continuing.

  4. git add the resolved files.

  5. git rebase --continue.

  6. Repeat until the rebase is complete, then return to the provider root and exit checkout mode:

./scripts/upstream.sh check_in
  1. Confirm upstream is detached rather than on pulumi/patch-checkout, then rerun upgrade-provider with --no-submit.

If git rebase --continue opens an editor in automation contexts, run GIT_EDITOR=true git rebase --continue.

Avoid:

  • Rerunning the tool before check_in; safe patched-provider preflight will reject leftover checkout state.

  • Hand-editing patches/*.patch unless intentionally doing raw patch surgery.

  • Direct edits under upstream/ outside checkout/check_in workflow.

Patch intent guidance
  • Docs-related patches usually replace or remove Terraform references. Preserve those changes when resolving conflicts.

  • A small, single-purpose docs patch that only removes an untranslatable section — for example an ## Import section written in Terraform-only import syntax — can sometimes be retired entirely and replaced with a targeted docs edit rule in provider/resources.go rather than resolving the conflict. Add the rule to ProviderInfo.DocRules.EditRules (e.g. a SkipSectionByHeader-style rule that drops the section by its header); verify the exact helper against the pulumi-terraform-bridge version in provider/go.mod. This avoids re-resolving the same conflict on every future upgrade, and when the patch was the repo's only one it can also remove the need for the upstream submodule (delete the .gitmodules entry).

  • Do not treat this as a default conflict-resolution tactic. Wholesale-replacing a docs patch with an edit rule only works when the patch is small and its intent maps cleanly onto a small rule. Patches that span multiple files or perform substantive rewrites should have their conflict resolved in place (per the guidance above), not be converted. Keep docs edit rules small and targeted — if reproducing the patch would require a large or brittle rule, resolve the conflict instead of converting it.

Upstream migrated from SDKv2 to Plugin Framework

Treat an upstream Terraform Plugin SDKv2-to-Plugin-Framework migration as a known migration path, not by itself as an architectural blocker. Common signals include:

  • Compiler errors such as undefined: <package>.Provider or code that still expects *schema.Provider.

  • Upstream go.mod dropping or making terraform-plugin-sdk/v2 indirect while adding terraform-plugin-framework.

  • Upstream release notes or commits that announce a Plugin Framework migration or SDKv2 removal.

  • make tfgen or upgrade-provider errors that a token mapping in provider/resources.go references a resource that is no longer present in the provider, and suggests removing that mapping. An unmuxed SDKv2 bridge (shimv2.NewProvider) can only see resources registered in the upstream SDKv2 ResourcesMap; a resource that upstream moved to the Plugin Framework is absent from the shimmed map, so its existing mapping looks stale. Do not remove the mapping on the tool's suggestion — that silently drops a resource users depend on. See "A mapped resource is reported missing" below.

Read the current bridge guide before editing provider entry points or imports:

Do not rely on remembered import paths or API signatures. The guides describe the current bridge release; verify the packages and APIs against the pulumi-terraform-bridge version selected by provider/go.mod before applying the migration.

First look for a public upstream package that constructs the Plugin Framework provider. If upstream exposes the constructor only from an unimportable internal/ package, use skill upstream-patches to add the smallest non-internal shim that returns the upstream provider. This is a legitimate new-patch case; keep the patch limited to exposing the constructor and document when it can be removed.

After applying the appropriate guide and any required patch, run focused provider builds or tests, then rerun upgrade-provider with --no-submit.

A mapped resource is reported missing (do not remove the mapping)

When tfgen finds a token mapping whose resource is no longer in the shimmed provider, it reports the resource as missing and suggests removing the mapping:

Pulumi token "<pulumi-token>" is mapped to TF provider resource "<tf_resource>", but no such resource found. Remove the mapping and try again

Before removing the mapping, verify the removal was real. The same "missing" error appears whether upstream deleted the resource or moved it to the Plugin Framework — an unmuxed SDKv2 bridge can't see a Framework resource — so confirm which happened:

  1. Inspect the upstream provider at the target tag. If the resource is gone from the SDKv2 ResourcesMap but a Plugin Framework equivalent now exists (a resource.Resource implementation registered in the framework provider's Resources method), it was migrated, not removed.

  2. Read the upstream CHANGELOG / release notes for the target version. A genuine removal or deprecation is normally announced; a Plugin Framework migration is often described only as an internal refactor.

  3. Confirm the token really left the generated schema by diffing against the default branch:

default_branch=$(git remote show origin | sed -n 's/.*HEAD branch: //p')
schema_path=$(find provider/cmd -path '*/schema.json' -print -quit)
diff <(git show "origin/${default_branch}:${schema_path}" | jq -r '.resources | keys[]') \
     <(jq -r '.resources | keys[]' "$schema_path")

Only if it was intentionally removed upstream should you drop the token mapping — and then call out the removal in the upgrade PR so reviewers can plan a deprecation. If it was migrated to the Plugin Framework, keep the resource by muxing the provider (follow the mux guide linked above) so the bridge serves it again; do not remove the mapping.

Upstream provider relies on ignored replace directives

When upgrade-provider fails during Update TF Provider with an upstream module resolution error like:

go get github.com/rancher/...: exit status 1:
go: github.com/rancher/terraform-provider-rancher2@... requires github.com/rancher/[email protected]: unknown revision v0.0.0

the upstream provider may have invalid-looking require entries that are only made valid by its own replace directives. Go ignores replace directives from dependency modules; only the main module's go.mod replacements are honored.

Fix in the Pulumi provider repo:

  1. Inspect upstream go.mod at the target tag or commit.

  2. Add the narrowest necessary upstream replace directives to provider/go.mod.

  3. Avoid copying the entire upstream replace block unless required; broad replacements can conflict with Pulumi or bridge dependencies.

  4. Run go mod tidy from provider/.

  5. Rerun upgrade-provider from the repo root with the target version explicit. Preserve the original major/non-major intent:

upgrade-provider pulumi/<provider> --repo-path . --no-submit --target-version <version>

Add --major only when the target upstream version crosses the current upstream major version. Passing --major for a same-major target makes upgrade-provider fail and can trigger unwanted major-version rewrite behavior.

If repo tools are managed by mise, run under the repo environment so Go and converter plugins match CI:

eval "$(mise env)" && upgrade-provider pulumi/<provider> --repo-path . --no-submit --target-version <version>

Example: pulumi-rancher2 upgrading to upstream terraform-provider-rancher2 v14.1.0 needed main-module replacements like:

replace (
  github.com/rancher/rancher => github.com/rancher/rancher v0.0.0-20260226161459-b186acea1a52
  github.com/rancher/rancher/pkg/apis => github.com/rancher/rancher/pkg/apis v0.0.0-20260226161459-b186acea1a52
  github.com/rancher/rancher/pkg/client => github.com/rancher/rancher/pkg/client v0.0.0-20260226161459-b186acea1a52
)

In that case, copying upstream OpenTelemetry replacements caused conflicts with Pulumi/bridge dependencies; the narrower Rancher-focused replacements were sufficient.

Upstream provider edits vendored dependency but module graph is stale

When make tfgen or upgrade-provider fails compiling the upstream Terraform provider with missing fields or methods from one of its dependencies, check whether upstream edited a vendored copy of that dependency without publishing or requiring a matching module version.

Common symptoms:

unknown field Destination in struct literal of type "github.com/f5devcentral/go-bigip".Gtmmonitor
client.CreateGtmMonitor undefined
client.GetGtmMonitor undefined

Confirm before fixing:

  1. Identify the dependency package in the compiler errors.

  2. Inspect the upstream provider tag or commit and compare its vendor/<module>/... files against the module version selected by provider/go.mod.

  3. If the needed fields or methods exist only under upstream vendor/, treat this as an upstream vendored-dependency patch case.

Fix in the Pulumi provider repo:

  1. Add or update the upstream Terraform provider submodule at upstream, pinned to the target upstream tag or commit.

  2. Set .gitmodules for the submodule to include ignore = dirty so an applied patch queue does not leave top-level git status noisy.

  3. Use the upstream-patches skill and ./scripts/upstream.sh checkout / check_in workflow to add a new patch containing only minimal go.mod files in the affected vendored dependency directories. This is an allowed new-patch case because the provider needs durable vendored module metadata:

./scripts/upstream.sh checkout
cd upstream
# Add minimal go.mod files under vendor/<module>/...
git add vendor/<module>/go.mod
git commit -m "Add module metadata for vendored <module>"
cd ..
./scripts/upstream.sh check_in
  1. Add narrow replace directives in provider/go.mod that point only the stale dependency modules at ../upstream/vendor/<module>.

  2. Run go mod tidy from provider/, then rerun make tfgen or upgrade-provider.

Example:

replace github.com/f5devcentral/go-bigip => ../upstream/vendor/github.com/f5devcentral/go-bigip

replace github.com/f5devcentral/go-bigip/f5teem => ../upstream/vendor/github.com/f5devcentral/go-bigip/f5teem

Avoid:

  • Copying the dependency into provider/third_party or another provider-owned vendor directory.

  • Replacing the whole upstream Terraform provider module with ../upstream unless necessary; this can break bridge documentation and example discovery because the module cache layout changes.

  • Hand-editing patches/*.patch instead of using upstream-patches, unless intentionally doing raw patch surgery.

When adding this kind of patch, make the tracking issue explicit and de-duplicated:

  1. Search existing issues first:

gh issue list --label "area/patch" --search "vendored dependency <module> in:title,body" --json number,title,url
  1. If no matching issue exists, create one with gh issue create, labeled area/patch, explaining why the patch exists and when it can be removed:

gh issue create \
  --title "Track vendored dependency patch for <module>" \
  --label "area/patch" \
  --body "$(cat <<'EOF'
The provider upgrade needs a patch because upstream vendors dependency changes
that are not available from the published module graph.

Removal criteria:
- Upstream requires a published dependency module containing the vendored changes, or
- The provider no longer needs the dependency replace directives.

Verification:
- Delete the patch and related provider/go.mod replace directives.
- Run make tfgen.
EOF
)"
  1. Link the issue from the upgrade PR's "Fixes applied to unblock upgrade" section.

Removal criteria should usually be: upstream requires a published dependency module containing the vendored changes, or the provider no longer needs the dependency replace directives. Verify removal by deleting the patch and replace directives, then rerunning make tfgen.

New resources missing module mapping

When new upstream resources appear, token mapping can fail with errors like:

* "google_observability_trace_scope": could not find a module that prefixes 'observability_trace_scope' in '[...]'

Fix by updating provider/resources.go (or the repo-equivalent file):

  1. Determine the Terraform module name (usually the first segment after the provider prefix). In the example, use observability.

  2. Add a module mapping in moduleMapping:

var moduleMapping = map[string]string{
  "observability": "Observability",
}
  1. If related resources already map to a different module, map the new resource individually instead of adding a new module key. Example:

DataSources: map[string]*tfbridge.DataSourceInfo{
  "aws_vpn_gateway": {Tok: awsDataSource(ec2Mod, "getVpnGateway")},
}

After updating, rerun upgrade-provider with --no-submit.

.NET duplicate file from nested Get suffix collision

When make generate_sdks fails during .NET SDK generation with an error like:

panic: fatal: An assertion has failed: duplicate file: Chaos/Inputs/ProbeTemplateHttpProbeMethodGetArgs.cs

look for a newly-added nested schema type where a parent type and a child field/type collide with the .NET generator's helper suffixes. Common pattern:

  • Parent object type: <X>

  • Child field/type: <X>Get

  • .NET state helper for the parent: <X>GetArgs.cs

  • .NET input helper for the child: <X>GetArgs.cs

Confirm the shape was introduced by the upstream bump before renaming. Compare the generated schema on the default branch with the upgrade branch. Derive the branch and schema path instead of assuming provider-specific names:

default_branch=$(git remote show origin | sed -n 's/.*HEAD branch: //p')
schema_path=$(find provider/cmd -path '*/schema.json' -print -quit)
git show "origin/${default_branch}:${schema_path}" | rg "<NestedTypeName>"
rg "<NestedTypeName>" "$schema_path"

Replace <NestedTypeName> with the colliding nested type prefix from the duplicate filename. If rg is unavailable, use grep -n for these literal searches.

Fix by applying a normal bridge Name override in provider/resources.go to rename the smallest nested field that causes the collision. Do not use CSharpName; it only changes C# property labels and does not change generated nested type filenames. Avoid schema post-processors unless there is no ordinary bridge mapping available.

Example:

"harness_chaos_probe_template": {
  Tok: harnessResource("chaos", "ProbeTemplate"),
  Fields: map[string]*tfbridge.SchemaInfo{
    "http_probe": {
      Elem: &tfbridge.SchemaInfo{
        Fields: map[string]*tfbridge.SchemaInfo{
          "method": {
            Elem: &tfbridge.SchemaInfo{
              Fields: map[string]*tfbridge.SchemaInfo{
                "get": {Name: "getMethod"},
              },
            },
          },
        },
      },
    },
  },
},

After updating the bridge mapping, rerun upgrade-provider --no-submit from the repo root so schema and SDKs regenerate consistently.

ID attribute wrong type (tfgen unresolved ID mapping)

When make tfgen fails with an error like:

error: Resource linode_producer_image_share_group has a problem: "id" attribute is of type "Int", expected type "string". To map this resource consider overriding the SchemaInfo.Type field or specifying ResourceInfo.ComputeID
error: There were 1 unresolved ID mapping errors

The upstream resource has an id attribute, but it is not a string. Fix it in provider/resources.go (or equivalent) by applying the override:

prov.P.ResourcesMap().Range(func(key string, value shim.Resource) bool {
  if value.Schema().Get("id").Type() != shim.TypeString {
    r := prov.Resources[key]
    if r.Fields == nil {
      r.Fields = make(map[string]*tfbridge.SchemaInfo, 1)
    }
    r.Fields["id"] = &tfbridge.SchemaInfo{Type: "string"}
  }
  return true
})
  • If the id type is not coercible to string, set ResourceInfo.ComputeID instead.

ID attribute is input type (tfgen unresolved ID mapping)

When make tfgen fails with an error like:

error: Resource cloudflare_zero_trust_access_ai_controls_mcp_server has a problem: an "id" input attribute is not allowed. To map this resource specify SchemaInfo.Name and ResourceInfo.ComputeID

The upstream resource exposes id as Optional/Required. Remap the input field to <resource_name>_id and delegate the ID to that new property. Convert the field name to Pulumi camelCase (for example, cloudflare_zero_trust_access_ai_controls_mcp_server -> zeroTrustAccessAiControlsMcpServerId).

"cloudflare_zero_trust_access_ai_controls_mcp_server": {
  Fields: map[string]*info.Schema{
    "id": {
      Name: "zeroTrustAccessAiControlsMcpServerId",
    },
  },
  ComputeID: tfbridge.DelegateIDField(resource.PropertyKey("zeroTrustAccessAiControlsMcpServerId"),
    "cloudflare", "https://github.com/pulumi/pulumi-cloudflare"),
},

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs a command-line tool

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
Pulumi
Publisher
Pulumi (Official)
Source
pulumi/agent-skills · package-maintenance/skills/pulumi-upgrade-provider · commit 82f222a
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Pulumi or Pulumi.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download pulumi-upgrade-provider.zip