Skip to content
This repository was archived by the owner on Feb 21, 2026. It is now read-only.

Commit 1f74883

Browse files
fix: resolve container OOM hangs from tsgo and --memory flag (#55)
* fix: resolve container OOM hangs from tsgo and --memory flag Two issues caused containers to hang indefinitely: 1. Apple Container's `--memory` flag treats bare numbers as bytes, not megabytes. `--memory 1024` = 1024 bytes, causing the VM to never boot. Fix: use proper suffix (`--memory 4G`). Ref: apple/container#1202 Ref: apple/container#1208 2. tsgo (TypeScript native compiler) has no default memory ceiling — Go doesn't auto-detect container memory limits, so tsgo allocates unbounded memory until the VM hangs under memory pressure. Fix: set GOMEMLIMIT=3GiB in entrypoint. Ref: microsoft/typescript-go#2125 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * make container memory configurable via CONTAINER_MEMORY env var Default 4G, configurable in .env. GOMEMLIMIT auto-derives from actual VM memory (75%) so it scales with any CONTAINER_MEMORY value. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2e8cc65 commit 1f74883

File tree

3 files changed

+10
-1
lines changed

3 files changed

+10
-1
lines changed

container/entrypoint.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ set -e
77
# Cap JS heap to prevent OOM
88
export NODE_OPTIONS="--max-old-space-size=2048"
99

10+
# Cap Go heap for tsgo (TypeScript native compiler) — Go doesn't auto-detect
11+
# container memory limits, so without this tsgo allocates unbounded memory and hangs.
12+
# Set to 75% of available RAM, leaving headroom for OS + other processes.
13+
# See: https://github.com/microsoft/typescript-go/issues/2125
14+
TOTAL_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
15+
export GOMEMLIMIT=$(( TOTAL_KB * 3 / 4 / 1024 ))MiB
16+
1017
# Configure git with GitHub token
1118
if [ -n "$GITHUB_TOKEN" ]; then
1219
gh auth setup-git 2>/dev/null || true

src/backends/local-backend.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import path from 'path';
1212
import {
1313
CONTAINER_IMAGE,
1414
CONTAINER_MAX_OUTPUT_SIZE,
15+
CONTAINER_MEMORY,
1516
CONTAINER_STARTUP_TIMEOUT,
1617
CONTAINER_TIMEOUT,
1718
DATA_DIR,
@@ -231,7 +232,7 @@ function buildVolumeMounts(
231232
}
232233

233234
function buildContainerArgs(mounts: VolumeMount[], containerName: string): string[] {
234-
const args: string[] = ['run', '-i', '--rm', '--name', containerName];
235+
const args: string[] = ['run', '-i', '--rm', '--memory', CONTAINER_MEMORY, '--name', containerName];
235236

236237
for (const mount of mounts) {
237238
if (mount.readonly) {

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const MAIN_GROUP_FOLDER = 'main';
2929

3030
export const CONTAINER_IMAGE =
3131
process.env.CONTAINER_IMAGE || 'nanoclaw-agent:latest';
32+
export const CONTAINER_MEMORY = process.env.CONTAINER_MEMORY || '4G';
3233
export const CONTAINER_TIMEOUT = parseInt(
3334
process.env.CONTAINER_TIMEOUT || '1800000',
3435
10,

0 commit comments

Comments
 (0)