Relationships
#1684 swamp serve OOMs on repos with 2000+ model definitions
Opened by webframp · 8/17/2026· Shipped 8/24/2026
Summary
swamp serve hits the V8 heap limit (4GB) and crashes during boot or shortly after the first workflow run on repos with 2000+ model definitions. The eager extension loading path at startup imports all extension bundles into memory simultaneously, exhausting the heap before serve becomes usable.
Reproduction
# Repo with ~2300 models across 30+ extension types
# (@webframp/aws/networking, inventory, alarms, logs, etc.)
swamp serve --auth-mode token --admins user:webframp --no-scheduleCrashes with:
Fatal JavaScript out of memory: Ineffective mark-compacts near heap limitMemory climbs from ~500MB to 4GB within 20 seconds. If it survives boot, the first workflow execution pushes it over.
Repos with ~100 models serve fine indefinitely.
Root Cause
serve.ts:1297 eagerly calls ensureLoaded() on all four registries:
await Promise.all([
modelRegistry.ensureLoaded(),
vaultTypeRegistry.ensureLoaded(),
datastoreTypeRegistry.ensureLoaded(),
reportRegistry.ensureLoaded(),
]);This triggers loadUserModels() -> loader.buildIndex() which imports every extension bundle into the V8 isolate simultaneously. For 30+ extension types with Zod schemas, method implementations, and output spec factories, this exceeds the 4GB V8 heap.
The CLI avoids this via lazy loading (setTypeLoader registers types as lazy entries, importing bundles only when a command targets that type). Serve bypasses the lazy path by calling ensureLoaded() which forces all types to load.
Suggested Fixes (ordered by impact/effort)
A. Lazy extension loading in serve (high impact, moderate effort)
The setTypeLoader mechanism already supports per-type lazy loading. At boot, only run buildIndex to populate the catalog (filesystem scan, no bundle imports). On first workflow step targeting a type, call ensureTypeLoaded(type). Remove or gate the eager ensureLoaded() calls behind a flag like --eager-extensions.
B. --serve-models whitelist (low effort, immediate fix)
Allow serve to specify which model types to load:
swamp serve --serve-models "@webframp/system,@webframp/network,command/shell"Everything else stays unloaded. Acceptable for dedicated serve instances running specific workflows.
C. Subprocess isolation for local steps (architecture alignment)
Run workflow steps in forked child processes (same as remote workers do). The serve process stays lean (orchestration only), each child loads only the extensions it needs, memory is reclaimed on exit.
Workaround
Use a minimal repo for serve containing only the models and extensions the target workflows need. Repos with 100-200 models work fine.
Environment
- swamp 20260816.214004.0-sha.6915a209
- Linux (WSL2, NixOS 26.11)
- Repo: 2317 models, 30+ extension types, filesystem datastore
Shipped
Click a lifecycle step above to view its details.