Skip to content

fix(registry): region-scope hcloud/cloudflare provider URNs#149

Merged
pedromvgomes merged 1 commit into
mainfrom
fix/region-scope-provider-urns
Jun 28, 2026
Merged

fix(registry): region-scope hcloud/cloudflare provider URNs#149
pedromvgomes merged 1 commit into
mainfrom
fix/region-scope-provider-urns

Conversation

@pedromvgomes

Copy link
Copy Markdown
Contributor

Problem

inforge preview fails for any environment that realizes Hetzner/Cloudflare resources in more than one scope with:

error: Duplicate resource URN 'urn:pulumi:prd::wardnet-infrastructure::pulumi:providers:hcloud::hcloud'

program.Run builds one provider registry per realization scope — one per region plus the region-less global slice — all over the same Pulumi context. Each registry lazily registered its singleton hcloud and cloudflare provider resources under the fixed names "hcloud"/"cloudflare". The first config to place Hetzner/Cloudflare resources in two scopes (e.g. a global compute host and a regional one) registers the same provider twice under one URN, and Pulumi fails the whole run before touching any resource.

This surfaced on wardnet-infrastructure#31, the first config with both a global (tenants) and a regional (edge) Hetzner host. Cloudflare had the identical latent collision (both scopes realize DNS) — it just hadn't surfaced because compute is created before DNS.

Fix

Scope the provider resource name by region: fmt.Sprintf("hcloud-%s", r.region) / cloudflare-%s. r.region is "global" for the global slice and the region name otherwise, so it is always present and unique per scope. The neon/infisical adapters are unaffected — they register per-resource names, not singleton providers.

Testing

  • New regression test TestProviderResourceNamesAreScopePerRegistry builds two registries (global + a region) over one Pulumi context and asserts each provider type is registered under distinct names. (The Pulumi mock monitor does not itself reject duplicate URNs, so the test asserts the name-uniqueness invariant directly — this is also why the bug was invisible to the prior nil-ctx registry test.) Verified failing pre-fix (got [hcloud hcloud]) and passing post-fix.
  • Added .agents/rules/registry-provider-names-are-region-scoped.md documenting the invariant for future singleton providers.
  • go build ./..., go test -race ./..., golangci-lint run ./... all clean.

Note

This changes the provider URN, which would force provider (and cascading resource) replacement on any pre-existing single-region stack. Confirmed with the maintainer that no such live stacks exist, so no pulumi.Aliases migration shim is needed.

Merge Commit Message

fix(registry): region-scope hcloud/cloudflare provider URNs

https://claude.ai/code/session_017Kyd98NzojozMZ19d5UCZ2

program.Run builds one provider registry per realization scope — one per
region plus the region-less global slice — all over the same Pulumi
context. Each registry lazily registered its hcloud and cloudflare
*provider* resources under the fixed names "hcloud"/"cloudflare", so once
a config realized Hetzner/Cloudflare resources in more than one scope the
two registrations collided on URN and failed the whole preview with
`Duplicate resource URN '…::pulumi:providers:hcloud::hcloud'`.

Scope the provider resource names by region (`hcloud-<region>`,
`cloudflare-<region>`); r.region is "global" for the global slice and the
region name otherwise, so it is always present and unique per scope.

Add a regression test that builds two registries over one context and
asserts the provider names are unique per scope (the Pulumi mock monitor
does not itself reject duplicate URNs), and a rule documenting the
invariant for future singleton providers added to the registry.

Claude-Session: https://claude.ai/code/session_017Kyd98NzojozMZ19d5UCZ2
@pedromvgomes pedromvgomes merged commit 61e0401 into main Jun 28, 2026
2 checks passed
@pedromvgomes pedromvgomes deleted the fix/region-scope-provider-urns branch June 28, 2026 06:34
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.

1 participant