Warren EC2 Capacity Report

Incident analysis — August 31, 2026. All timestamps UTC unless noted.

What this actually looks like from the outside

When memory fills up, work goes into a queue. Warren gets slow.
Some tasks need an external connection — the Miro MCP server, for instance, needs a handshake to complete within 30 seconds. Under memory pressure the event loop stalls, sometimes for over a minute. The handshake never finishes and times out.

Warren then reports that he’s lost access to Miro.
He hasn’t. The OAuth token is valid, the server is healthy, all 57 tools are available. Network latency to the endpoint is under half a second. He simply couldn’t complete the handshake in time.

The same thing happened this morning with Google Workspace: reported as missing credentials, when the credentials were intact and untouched since installation.

The consequence isn’t just that Warren is slow. It’s that he diagnoses incorrectly.
He reports problems that don’t exist. Anyone investigating then goes looking at credentials, permissions, and integrations that were never broken — while the real cause is that the box ran out of room to work.

Meanwhile, 96 user messages were silently discarded across 15 sessions in 24 hours, with no error shown to anyone who sent them.

Finding: Inherited V8 Heap Setting

~/.config/systemd/user/openclaw-gateway.service, line 25 Environment=NODE_OPTIONS=--max-old-space-size=6144

This setting was tuned for the DGX Spark, where 6 GiB was 5% of 121 GB physical memory — harmless. It was carried over unchanged on Aug 20 when the service unit was copied to EC2. Nobody adjusted it for the new box’s RAM.

On this t3.large, 6 GiB is 79% of 7.6 GB physical. V8 is permitted to grow to 6 GiB before triggering major garbage collection. When it finally collects at that size, the GC pause freezes the Node.js event loop — up to 75 seconds in today’s worst case. That’s 2.5× the 30-second MCP handshake timeout, which is why Miro initialization fails under load.

Removing this line lets the adaptive default take over: 3,909 MiB (50% of physical). V8 would cap at ~3.9 GiB and collect earlier, with shorter pauses. The spikes would still happen but would plateau lower — likely under the 30s MCP timeout instead of over it.

This is testable before any instance resize. It costs nothing, requires only removing line 25 from the service unit and running systemctl --user daemon-reload. The next scheduled restart is at 04:00 PDT.

Memory Growth Pattern

The memory pattern is spike-and-drop, not leak. The idle floor between active windows is flat at 1.40–1.62 GiB for hours with no growth. Concurrent sessions drive spikes; when they end, RSS falls back to baseline.

RSS readings over time since restart at 11:00 UTC — journalctl + diagnostics/memory UTC RSS Heap Context ─────────────────────────────────────────────────── 11:56 1.34 Post-restart baseline 12:05 2.38 2.02 Critical — concurrent session spike 12:10 1.81 Drops back ─── gap: no pressure events 14:30–18:50 ─── 14:29 2.17 1.91 ─── SOC for AI Miro work begins ─── 18:50 2.59 1.60 Concurrent sessions ramp 18:55 3.03 2.66 Critical 18:56 2.39 1.11 V8 GC fires, heap halves 19:08 3.67 3.17 Peak of window 1 19:10 2.69 0.88 GC fires again 19:29 1.40 1.05 Sessions end, drops to floor ─── idle: 3 hours flat ─── 19:51 1.44 1.03 No growth 20:34 1.44 1.04 No growth 21:08 1.52 1.10 No growth 22:04 1.46 1.03 No growth 22:34 1.62 1.15 No growth ─── SOC subagent burst begins ─── 22:45 1.75 1.30 Activity starts 22:45 2.86 2.49 30 seconds later: +1.1 GiB 22:46 3.87 3.39 1 minute later: +2.1 GiB 22:51 3.02 1.37 GC fires 22:56 3.82 2.99 Climbs right back 23:01 3.94 3.48 23:12 4.06 3.55 Day peak (sampled)

Concurrent Opus 4-6/4-8 sessions each allocate 1–2 GiB of heap for context windows, model payloads, and tool schemas. Two concurrent sessions fit. Three push past the pressure threshold. The box has capacity for one heavy session at a time with headroom, but not the concurrent workload it actually runs.

Capacity Context

The heap setting is the first thing to fix, but the underlying capacity question remains: is this box large enough for the concurrent workload? Before spending on a resize, the config fix is testable at zero cost and the next restart is already scheduled.

DGX Spark (prior host)

13%
Peak memory utilization

16.3 GB peak / 121 GB available
4 TB disk · GPU compute
21h uptime before peak

EC2 t3.large (current)

85%
Peak memory utilization

6.48 GB peak / 7.6 GB available
No swap · No cgroup limit
1.12 GB to OOM killer at peak

1. Memory Evidence

Cgroup readings (raw, from kernel)

Source: /sys/fs/cgroup/.../openclaw-gateway.service/memory.* memory.peak: 6,956,515,328 bytes (6.48 GiB) memory.current: 4,339,146,752 bytes (4.04 GiB at time of read) memory.max: max (no cgroup limit set) System: t3.large — 7.6 GiB physical, 0 B swap Margin at peak: 1.12 GiB to OOM killer

Critical memory pressure events (last 24h)

The gateway's diagnostic subsystem fired critical memory pressure alerts throughout the day. These are the 10 highest RSS readings observed:

Source: journalctl --user -u openclaw-gateway | grep "memory pressure" 4.06 GiB ← highest sampled (23:12 UTC) 3.94 GiB 3.90 GiB 3.88 GiB 3.87 GiB 3.82 GiB 3.67 GiB 3.55 GiB 3.24 GiB 3.10 GiB

Note: sampled RSS values are lower than the cgroup peak (6.48 GiB) because diagnostics fire every ~30 seconds. The true peak occurred between samples.

2. Downstream Failures

2a. Silent message loss

96
user messages silently discarded in 24 hours, across 15 sessions

When a new message arrives on a session that already has a queued-but-unprocessed message, the gateway prunes the older message to prevent consecutive user turns. No error is returned to the sender. The message disappears without trace.

Session IDMessages Lost
09f275e718
67218c4416
38b68fc1 (Victor DM)16
886d532712
ef6e79345
c575b9d55
+ 9 more sessions (1–4 each)

2b. Miro MCP timeouts

The Miro MCP server requires a 30-second initialization handshake over streamable-http. When the event loop is blocked by memory pressure, the handshake cannot complete.

Network test (curl, bypassing gateway):

5 consecutive requests to mcp.miro.com connect: 7–10ms total: 233–565ms status: 401 connect: 7–10ms total: 233–565ms status: 401 connect: 7–10ms total: 233–565ms status: 401 connect: 7–10ms total: 233–565ms status: 401 connect: 7–10ms total: 233–565ms status: 401 All sub-second. Network path is healthy.

Correlation with memory pressure: Every Miro MCP timeout in the last 24 hours occurred during or immediately after a critical memory pressure window. The event loop P99 delay peaked at 75.4 seconds — 2.5× the MCP initialization timeout of 30 seconds.

18:55 UTC
Critical memory pressure — RSS 3.03 GiB
19:08 UTC
Critical memory pressure — RSS 3.67 GiB (session peak)
19:29 UTC
Miro MCP timeout
21:07–21:24 UTC
3 Miro MCP timeouts in 17 minutes
22:10 UTC
Miro MCP timeout
22:20 UTC
Miro MCP connects successfully — 57 tools loaded
22:28 UTC
Miro Slide 9 deployed successfully (24 items)
22:42–22:44 UTC
3 Miro MCP timeouts
22:45 UTC
Critical memory pressure — RSS 3.87 GiB
22:46 UTC
Critical memory pressure — RSS 3.87 GiB, heap 3.39 GiB
22:51 UTC
Critical memory pressure — RSS 3.02 GiB
22:55 UTC
Miro MCP timeout
23:01 UTC
Critical memory pressure — RSS 3.94 GiB
23:06 UTC
Miro MCP timeout
23:12 UTC
Critical memory pressure — RSS 4.06 GiB (day peak)
23:39 UTC
Miro MCP timeout

2c. DM session wedge

At 22:54 UTC, critical memory pressure triggered an internal abort-for-restart. Two active agent runs were killed mid-flight. The Victor DM session (38b68fc1) recovered into a zombie state — permanently queued at q=1, idle, last=reply_operation:ended — where it accepted no new processing. Every subsequent message was pruned as an orphan.

Source: journalctl diagnostics — abort sequence 22:51:24 — critical memory (RSS 3.02 GiB, threshold 3 GiB) 22:54:27 — AbortError: agent run aborted for restart (2 sessions killed) 22:55:06 — GatewayDrainingError: new tasks not accepted 23:02:39 — IngressAdoptionLostError: ingress adoption lost: guillotined 23:05+ — DM session enters zombie state, orphan pruning begins 23:14:02 — Event loop P99 spike: 75,430ms (75 seconds)

The session remained wedged for 35+ minutes until the diagnostic investigation in this thread began. No self-recovery mechanism fired.

2d. Exec denials correlating with memory pressure

Subagent sessions spawned during the Miro deck work hit exec denied: host=gateway security=deny errors. These cluster tightly with critical memory pressure events:

Exec DeniedNearest CriticalGap
19:07:0019:08:311m 31s
19:09:0419:08:3133s
22:43:5422:45:371m 43s
22:45:4522:45:378s
22:56:0022:56:3838s
00:52:5200:20:4632m ← outlier
01:19:1901:17:591m 20s
01:28:4901:28:512s
01:34:5501:34:0649s
01:40:2901:39:171m 12s
01:41:2301:39:172m 6s
01:43:3701:44:3356s
01:44:3001:44:333s
01:45:1601:44:3343s

14 of 15 exec denials occurred within 2 minutes of a critical memory pressure event. The tightest correlation: 01:28:49 deny against 01:28:51 critical — a 2-second gap.

Caveats: The 00:52 outlier sits 32 minutes from the nearest critical event and may not be pressure-related. The 23:01–23:32 window shows 7 consecutive critical events with zero exec denials — this likely reflects no exec attempts during that period (the diagnostic investigation was running from a different session with exec enabled), not a return to health.

Why this matters: This symptom cost the most investigation time. Warren observed exec denials on subagent sessions, concluded the sessions had lost tool policy, and proposed workarounds for a problem that didn’t exist. The subagents were spawned because memory pressure made the Miro MCP unavailable from the main session. The exec denials were legitimate policy restrictions on those subagents — but the reason the subagents existed at all was the cascading failure from memory pressure. The same misdiagnosis pattern as Miro and GWS: a real symptom attributed to the wrong cause, sending investigation down the wrong path.

3. Event Loop Impact

The Node.js event loop — which services all gateway operations including Slack socket mode, MCP handshakes, SQLite transactions, and model response streaming — showed sustained degradation during memory pressure windows:

MetricNormalUnder Pressure
Event loop P99 delay<25ms75,430ms
Event loop utilization0.09–0.151.0 (saturated)
CPU core ratio0.151.39
Heartbeat interval30s97s (delayed 31–33s)
SQLite transaction holdNot loggedRepeated "slow" warnings

4. Unrelated: Google Workspace

Unrelated Fixed

GWS API calls failed on Aug 31 morning because the agent called gws (OpenClaw plugin CLI, no OAuth configured) instead of ~/bin/gws-sa (service account wrapper installed by Victor on Aug 28). The service account credentials, token refresh script, and API access all work correctly. A standing rule was added to AGENTS.md to prevent recurrence. Not a capacity issue.

5. System Context

PropertyValue
Instance typet3.large (confirmed from IMDS)
vCPU2
RAM7.6 GiB
SwapNone configured
Disk48 GB
OSUbuntu 24.04 x86_64
Node.jsv22.23.2
BootAug 20, 15:06 UTC
Daily restart04:00 PDT via openclaw-backup.service
Restart historyNRestarts=0, no StartLimitBurst triggers, clean stop/start every cycle
IAM identityt-and-c-ec2-role (instance role only; no IAM user credentials on disk)
BackpressureNone — gateway accepts all inbound work regardless of memory/CPU state