Description
PLATFORM_JAVA_HEAP_MAX=2g (.env) is too small for a sustained-write local node, and the failure mode is a silent one: the JVM OOMs, the platform gets stuck oscillating ACTIVE → CHECKING and never returns to ACTIVE, so every transaction is rejected PLATFORM_NOT_ACTIVE — while docker ps continues to report network-node ... (healthy) the entire time, because the container still accepts connections.
Observed twice in ~24 h on the same node, plus one ISS. Evidence from /opt/hgcapp/services-hedera/HapiApp2.0/output/gc.log:
Max Capacity: 2048M(100%)
Critical: Allocation Stall … 4583.883 / 9653.581 ms
9.6-second allocation stalls — threads blocked because the JVM cannot allocate. That produces the HealthMonitor has been unhealthy for 10.6 h / ~10M-unhandled-task backlog in swirlds.log and the death spiral.
Note this is a JVM heap ceiling, not a container limit: the container sat at ~1.4 GiB of its 8 GiB NETWORK_NODE_MEM_LIMIT on a 48 GB host. Anyone debugging by looking at host or container memory pressure finds nothing wrong.
Raising PLATFORM_JAVA_HEAP_MAX to 4g (still half the container cap, leaving room for ~73 MB metaspace + native + ZGC overhead) has held since. Verified the JVM actually took it by reading Max Capacity: 4096M from gc.log rather than trusting the env var.
Steps to reproduce
hedera start -d, leave running with sustained consensus submissions (the bundled mirror-node-monitor alone is enough — it publishes ~1.8 tx/s continuously)
- After some hours: transactions fail
PLATFORM_NOT_ACTIVE; docker ps still says healthy
docker exec network-node sh -c 'tail /opt/hgcapp/services-hedera/HapiApp2.0/output/swirlds.log' → java.lang.OutOfMemoryError: Java heap space
Expected behavior
Either a larger default heap (4g was sufficient here), or a documented note that sustained-write workloads need PLATFORM_JAVA_HEAP_MAX raised, and ideally a healthcheck that asserts platform status (swirlds.log … newStatus":"ACTIVE") rather than container reachability — so an OOM-dead node reports unhealthy instead of healthy.
Environment
- @hashgraph/hedera-local 2.40.2, macOS 26.5 (Apple Silicon), colima 0.10.1, 6 CPU / 10 GiB VM, host 48 GB
Notes
Possibly the root cause behind the closed #800 (PLATFORM_NOT_ACTIVE after a while) — that report has the same symptom and timeline, and no heap analysis. Recovery is docker restart network-node (volume-preserving, replays saved state to ACTIVE in ~45 s) — not hedera stop, which destroys the ledger (#1390).
Description
PLATFORM_JAVA_HEAP_MAX=2g(.env) is too small for a sustained-write local node, and the failure mode is a silent one: the JVM OOMs, the platform gets stuck oscillatingACTIVE → CHECKINGand never returns toACTIVE, so every transaction is rejectedPLATFORM_NOT_ACTIVE— whiledocker pscontinues to reportnetwork-node ... (healthy)the entire time, because the container still accepts connections.Observed twice in ~24 h on the same node, plus one ISS. Evidence from
/opt/hgcapp/services-hedera/HapiApp2.0/output/gc.log:9.6-second allocation stalls — threads blocked because the JVM cannot allocate. That produces the
HealthMonitor has been unhealthy for 10.6 h/ ~10M-unhandled-task backlog inswirlds.logand the death spiral.Note this is a JVM heap ceiling, not a container limit: the container sat at ~1.4 GiB of its 8 GiB
NETWORK_NODE_MEM_LIMITon a 48 GB host. Anyone debugging by looking at host or container memory pressure finds nothing wrong.Raising
PLATFORM_JAVA_HEAP_MAXto4g(still half the container cap, leaving room for ~73 MB metaspace + native + ZGC overhead) has held since. Verified the JVM actually took it by readingMax Capacity: 4096Mfromgc.lograther than trusting the env var.Steps to reproduce
hedera start -d, leave running with sustained consensus submissions (the bundledmirror-node-monitoralone is enough — it publishes ~1.8 tx/s continuously)PLATFORM_NOT_ACTIVE;docker psstill sayshealthydocker exec network-node sh -c 'tail /opt/hgcapp/services-hedera/HapiApp2.0/output/swirlds.log'→java.lang.OutOfMemoryError: Java heap spaceExpected behavior
Either a larger default heap (
4gwas sufficient here), or a documented note that sustained-write workloads needPLATFORM_JAVA_HEAP_MAXraised, and ideally a healthcheck that asserts platform status (swirlds.log … newStatus":"ACTIVE") rather than container reachability — so an OOM-dead node reports unhealthy instead of healthy.Environment
Notes
Possibly the root cause behind the closed #800 (
PLATFORM_NOT_ACTIVEafter a while) — that report has the same symptom and timeline, and no heap analysis. Recovery isdocker restart network-node(volume-preserving, replays saved state toACTIVEin ~45 s) — nothedera stop, which destroys the ledger (#1390).