Relationships
#2702 Two pulled extensions providing one type + a rebuilt catalog brick every command (I-Repo-1 at startup reconcile, even rm/--repair)
Opened by hammz · 9/29/2026· Shipped 9/29/2026
Description
When two pulled extensions provide the same (kind, type) and the extension catalog is rebuilt from scratch, the startup reconcile fails I-Repo-1 and rolls back. The reconcile runs during CLI startup, so every command in the repo then exits 1 with the same error. That includes swamp doctor extensions --repair, swamp extension rm of either extension, model type search and extension list. The catalog stays empty and no swamp command can recover it.
This is the same "every command bricked" symptom as swamp-club#1065, from a different cause.
Found while e2e-validating swamp-club#2490. It reproduces on the latest release (20260929.154804.0-sha.80c0526f) and on the #2490 branch. It is not caused by #2490.
Steps to reproduce
With a warm catalog, the repo works: the type resolves to the first provider. Deleting .swamp/_extension_catalog.db wedges it.
swamp repo init repo --tool none, thenswamp extension pull @swamp/aws/cur.- Make a second pulled extension that provides the same type. The repro copies
.swamp/pulled-extensions/@swamp/aws/curto.swamp/pulled-extensions/@aaa/cur, renames it inmanifest.yaml, and adds an@aaa/curentry toextensions/models/upstream_extensions.json. swamp model type describe @swamp/aws/cur/report-definition --json→ rc=0.rm .swamp/_extension_catalog.db*- Every command now fails:
[rc=1] swamp model type describe @swamp/aws/cur/report-definition --json
[rc=1] swamp model type search --json
[rc=1] swamp extension list --json
[rc=1] swamp doctor extensions --json
[rc=1] swamp doctor extensions --repair -y
[rc=1] swamp extension rm @aaa/cur -y
[rc=1] swamp extension rm @swamp/aws/cur -y
bundle_types rows: 0DuplicateTypeError: I-Repo-1 violation: type "@swamp/aws/cur/report-definition" (kind=model) claimed by both @aaa/cur@2026.09.29.1 at <repo>/.swamp/pulled-extensions/@aaa/cur/models/report_definition.ts and @swamp/aws/cur@2026.09.29.1 at <repo>/.swamp/pulled-extensions/@swamp/aws/cur/models/report_definition.ts. ROLLBACK applied.
at ExtensionRepository.assertIRepo1 (extension_repository.ts:632)
at ExtensionRepository.saveAll (extension_repository.ts:237)
at ReconcileFromDiskService.execute (reconcile_from_disk_service.ts:251)
at runReconcile (cli/mod.ts:640)
at configureStartupExtensions (cli/mod.ts:662)A self-contained script (it needs jq; sqlite3 is optional):
SW=swamp; W=$(mktemp -d); export SWAMP_HOME=$W/home XDG_CONFIG_HOME=$W/xdg
(cd $W && $SW repo init repo --tool none) && cd $W/repo
$SW extension pull @swamp/aws/cur -y
P=.swamp/pulled-extensions; mkdir -p $P/@aaa && cp -a $P/@swamp/aws/cur $P/@aaa/cur
sed -i 's#^name:.*#name: "@aaa/cur"#' $P/@aaa/cur/manifest.yaml
LF=extensions/models/upstream_extensions.json
jq '. + {"@aaa/cur": (.["@swamp/aws/cur"] | .files |= map(sub("@swamp/aws/cur"; "@aaa/cur")))}' $LF > $LF.t && mv $LF.t $LF
$SW model type describe @swamp/aws/cur/report-definition --json >/dev/null; echo "warm rc=$?"
rm -f .swamp/_extension_catalog.db*
$SW model type search --json; echo "rc=$?"
$SW extension rm @aaa/cur -y; echo "rc=$?"How a repo can get here
- The catalog gets rebuilt from scratch when
.swamp/_extension_catalog.dbis deleted (a common troubleshooting step), on a fresh machine or clone (.swamp/is gitignored), or on a bundle-layout cold rebuild. - Two pulled providers of one type:
- The repro makes the second provider by hand.
extension pullof a second provider is normally rejected withDuplicateTypeError.- Not verified: a committed
upstream_extensions.jsonthat lists two providers (e.g. after merging two branches that each pulled one), installed withswamp extension installon a fresh clone, should give the same state without any hand editing. That would need two published extensions that collide.
Expected
- A startup integrity failure should not brick unrelated commands. At minimum,
doctor extensions --repairandextension rmmust still be reachable, since they are the tools that fix this state. The same point is in the "Expected" section of #1065. - Pulled-vs-pulled conflicts found by the startup reconcile should settle deterministically, not roll back. The loader already does this (
settlePulledTypeConflicts, keep the incumbent and warn, #2490). Alternatively, the reconcile could index the first provider and mark the other as a conflict thatdoctorreports.
Workaround
Delete one provider's directory by hand, e.g. rm -rf .swamp/pulled-extensions/@aaa/cur. The next command works. The lockfile still lists the removed extension until swamp extension rm is run.
Shipped
Click a lifecycle step above to view its details.
Sign in to post a ripple.