Skip to main content
← Back to list
01Issue
BugShippedSwamp CLIPublic
Assigneeshammz

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.

  1. swamp repo init repo --tool none, then swamp extension pull @swamp/aws/cur.
  2. Make a second pulled extension that provides the same type. The repro copies .swamp/pulled-extensions/@swamp/aws/cur to .swamp/pulled-extensions/@aaa/cur, renames it in manifest.yaml, and adds an @aaa/cur entry to extensions/models/upstream_extensions.json.
  3. swamp model type describe @swamp/aws/cur/report-definition --json → rc=0.
  4. rm .swamp/_extension_catalog.db*
  5. 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: 0
DuplicateTypeError: 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.db is 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 pull of a second provider is normally rejected with DuplicateTypeError.
    • Not verified: a committed upstream_extensions.json that lists two providers (e.g. after merging two branches that each pulled one), installed with swamp extension install on 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 --repair and extension rm must 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 that doctor reports.

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.

02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 7 MOREREVIEW+ 8 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

9/29/2026, 5:42:56 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
hammz assigned hammz9/29/2026, 4:24:11 PM

Sign in to post a ripple.