ハードコードされた5MBメディアストア制限が、チャネル制限が適用される前に生成メディアをブロック
OpenClawは、ランタイムbundle内のハードコードされた5MBステージング制限を適用し、チャネルおよびagent-levelメディア設定をサイレントに無効にします。これにより、有効なlarge mediaワークフローで「Media exceeds 5MB limit」エラーが発生します。
🔍 症状
ハードコードされたメディアステージングの上限は、いくつかの異なるエラーパターンで発生します:
主なエラー現象
5MBを超えるメディアファイルをステージングまたは返そうとすると、以下のエラーが発生します:
Error: Media exceeds 5MB limit
at MediaStore.validateSize (dist/store-CA7OW_2w.js:XX:XX)
at MediaStore.stage (dist/store-CA7OW_2w.js:XX:XX)
at MediaPipeline.processOutput (dist/store-CA7OW_2w.js:XX:XX)
at async CodexAgent.handleToolResult (dist/store-CA7OW_2w.js:XX:XX)メディア処理時のエラーフロー
このエラーは、メディアパイプラインのステージング検証フェーズで発生し、下流のチャンネル固有の上限制解決の前です:
- 取り込みフェーズ — エージェントが生成または受信したメディア
- ステージング検証 —
dist/store-CA7OW_2w.js内のハードコードされた5MBチェック ← 失敗ポイント - チャンネル解決 — チャンネル/エージェントのメディア上限(到達しない)
- 配信 — 設定されたチャンネルへの出力
問題が発生する条件
- 5MBを超えるファイルを生成するビデオ生成ワークフロー
- しきい値を超えるフレームデータを持つマルチイメージ合成やGIF
- 長い継続時間と高サンプルレートのオーディオファイル
openclaw.media.stage()を通じてステージングされるすべてのメディアツール出力
サイレントオーバーライド動作
ハードコードされた上限は有効なチャンネル設定をサイレントにオーバーライドします。この動作を観測するユーザーは以下を気づくかもしれません:
# チャンネル設定では25MBの上限が指定されている
openclaw config get channels.slack.media.maxBytes
# 出力: 26214400 (25MB)
# しかし生成されたメディアは5MBのしきい値で失敗する
openclaw run --tool video-generate --prompt "Generate a 30-second clip"
# エラー: Media exceeds 5MB limitこれは、設定された上限が無効であるかのように見える、誤解を招くユーザー体験を生み出します。
🧠 原因
アーキテクチャの問題: 早すぎる検証ゲート
根本原因は、OpenClawのメディアパイプラインアーキテクチャにおける検証順序の問題です。バンドルされたランタイムファイルdist/store-CA7OW_2w.jsには以下が含まれています:
// From dist/store-CA7OW_2w.js
const MEDIA_MAX_BYTES = 5 * 1024 * 1024; // 5,242,880 bytes
class MediaStore {
validateSize(bufferOrPath) {
const size = this.getSize(bufferOrPath);
if (size > MEDIA_MAX_BYTES) {
throw new MediaLimitError(
`Media exceeds ${MEDIA_MAX_BYTES} limit`
);
}
// ... downstream processing
}
}これが問題を引き起こす理由
- 設定範囲外のハードコード定数 —
MEDIA_MAX_BYTESの値はビルド時にランタイムバンドルにコンパイルされ、設定ファイル、環境変数、またはランタイム設定ではオーバーライドできません。 - パイプライン上の位置 — 検証は
MediaStore.validateSize()メソッドで発生し、チャンネル固有の上限制解決の前にステージングフェーズで呼び出されます。 - 設定の継承がない — ステージングレイヤーは、このチェックを適用する際に
channel.media.maxBytes、agent.mediaLimits、またはその他の設定階層を参照しません。 - サイレント失敗パス — 5MBのしきい値を超えると、構成可能な上限を参照したり、ステージング上限をオーバーライドするためのガイダンスを提供したりせずにエラーがスローされます。
想定される上限階層と実際の階層
OpenClawの設計では、複数のソースから実効上限を解決する上限階層を想定しているようです:
// 想定される解決順序(到達しない):
effectiveLimit = min(
channel.media.maxBytes, // 例:Slackでは25MB
agent.mediaLimits.maxBytes, // 特定エージェントでは10MB
globalDefaults.maxBytes // 例:グローバル天井は50MB
)ただし、実際の実行パスは、これらの解決パスのいずれかが実行される前に、ハードコードされた5MBの値にショートサーキットします。
なぜこれが存在するのか
5MBのハードルは、以下を防ぐための安全措置として始まった可能性があります:
- ステージング中のメモリ消費の無制限化防止
- 「クイック」メディア操作のための合理的な天井の強制
- ステージングレイヤーで予測可能なメモリ境界の確保
ただし、透明な定数としてではなく、文書化された設定可能なパラメータとして実装されていません。
🛠️ 解決手順
解決策1: 実効メディア上限からステージング上限を導出する(推奨)
MediaStoreクラスを修正して、ステージング上限を設定階層から解決するようにします:
// Before (dist/store-CA7OW_2w.js)
const MEDIA_MAX_BYTES = 5 * 1024 * 1024;
class MediaStore {
validateSize(bufferOrPath) {
const size = this.getSize(bufferOrPath);
if (size > MEDIA_MAX_BYTES) { /* error */ }
}
}// After (dist/store-CA7OW_2w.js)
const DEFAULT_STAGING_MAX_BYTES = 50 * 1024 * 1024; // 50MB default
class MediaStore {
constructor(options = {}) {
super(options);
this._effectiveLimit = null;
}
getEffectiveLimit(context) {
if (this._effectiveLimit !== null) {
return this._effectiveLimit;
}
// Resolve from configuration hierarchy
const configuredLimits = [
context?.channel?.media?.maxBytes,
context?.agent?.mediaLimits?.maxBytes,
context?.config?.media?.stagingMaxBytes
].filter(limit => Number.isInteger(limit) && limit > 0);
this._effectiveLimit = configuredLimits.length > 0
? Math.min(...configuredLimits)
: DEFAULT_STAGING_MAX_BYTES;
return this._effectiveLimit;
}
validateSize(bufferOrPath, context = {}) {
const size = this.getSize(bufferOrPath);
const effectiveLimit = this.getEffectiveLimit(context);
if (size > effectiveLimit) {
throw new MediaLimitError(
`Media size (${size} bytes) exceeds effective limit of ${effectiveLimit} bytes ` +
`(resolved from: ${JSON.stringify(context.channel?.media?.maxBytes ? 'channel' : 'default'})`
);
}
}
}解決策2: ステージング上限設定の追加(ワークアラウンド)
上記の修正がリリースで利用可能になるまで、ステージング上限を設定システムに追加します:
ステップ1: 設定スキーマを更新する
# Add to openclaw.config.schema.json or equivalent
{
"media": {
"stagingMaxBytes": {
"type": "integer",
"default": 52428800,
"description": "Maximum media size (in bytes) for staging/store operations",
"env": "OPENCLAW_MEDIA_STAGING_MAX_BYTES"
}
}
}ステップ2: MediaStoreの初期化を修正する
class MediaStore {
constructor(options = {}) {
const config = options.config || globalOpenClawConfig;
this._stagingLimit = config.media?.stagingMaxBytes || DEFAULT_STAGING_MAX_BYTES;
}
}ステップ3: 設定経由でこの値を変更する
# In openclaw.config.yaml or openclaw.config.js
media:
stagingMaxBytes: 26214400 # 25MB
# Or via environment variable
export OPENCLAW_MEDIA_STAGING_MAX_BYTES=26214400解決策3: 一時的なランタイムオーバーライド(即座のワークアラウンド)
バンドルを直接変更できない場合は、メディア操作前にモンキーパッチを適用します:
// patch-media-limit.js
const originalRequire = module.constructor.prototype.require;
module.constructor.prototype.require = function(id) {
const module = originalRequire.apply(this, arguments);
if (id === './store' || id.includes('store-CA7OW')) {
if (module.MediaStore) {
const OriginalMediaStore = module.MediaStore;
module.MediaStore = class PatchedMediaStore extends OriginalMediaStore {
validateSize(...args) {
// Override staging limit for this session
const originalLimit = this.constructor.MEDIA_MAX_BYTES;
try {
this.constructor.MEDIA_MAX_BYTES = process.env.OPENCLAW_STAGING_MAX_BYTES || 52428800;
return super.validateSize(...args);
} finally {
this.constructor.MEDIA_MAX_BYTES = originalLimit;
}
}
};
}
}
return module;
};
// Load before OpenClaw initialization
require('./patch-media-limit');
const { OpenClaw } = require('openclaw');🧪 検証
修正を適用した後は、以下の検証手順で解決を確認します:
前提条件
# Ensure OpenClaw version includes the fix or workaround
openclaw --version
# Expected: 2026.4.12+ (or patched 2026.4.11)
# Verify configuration is set correctly
openclaw config get media.stagingMaxBytes
# Expected: > 5242880 (if explicitly set)
openclaw config get channels[0].media.maxBytes
# Expected: Your configured channel limit (e.g., 26214400 for 25MB)検証テスト: 元の5MB上限を超えるメディアをステージングする
# Create a test file exceeding 5MB (6MB)
dd if=/dev/urandom of=/tmp/test-media-6mb.bin bs=1M count=6
# Attempt to stage through OpenClaw media pipeline
node -e "
const { MediaStore } = require('openclaw/dist/store-CA7OW_2w');
const store = new MediaStore();
const fs = require('fs');
try {
const buffer = fs.readFileSync('/tmp/test-media-6mb.bin');
store.validateSize(buffer);
console.log('SUCCESS: Media staged without error');
console.log('Size validated:', buffer.length, 'bytes');
} catch (err) {
console.error('FAILED:', err.message);
process.exit(1);
}
"
# Expected output after fix:
# SUCCESS: Media staged without error
# Size validated: 6291456 bytes検証テスト: ビデオ生成ワークフロー
# Run a video generation that produces > 5MB output
openclaw run \
--tool video-generate \
--prompt "Generate a 45-second animated landscape" \
--output ./output/video.mp4
# Expected after fix:
# - Command completes without "Media exceeds 5MB limit" error
# - Output file exists and has expected size
ls -lh ./output/video.mp4
# Expected: file size > 5MB if generated successfully検証テスト: 上限階層の解決
# Test that effective limit respects the minimum of all configured limits
node -e "
const { MediaStore } = require('openclaw/dist/store-CA7OW_2w');
const store = new MediaStore({
config: {
media: { stagingMaxBytes: 10485760 } // 10MB
},
channel: {
media: { maxBytes: 5242880 } // 5MB
},
agent: {
mediaLimits: { maxBytes: 15728640 } // 15MB
}
});
const context = store.getEffectiveLimit({
config: store._config,
channel: store._config.channel,
agent: store._config.agent
});
console.log('Effective limit:', context, 'bytes');
console.log('Expected: 5242880 (minimum of channel: 5MB)');
console.log('Result:', context === 5242880 ? 'PASS' : 'FAIL');
"検証テスト: エラーメッセージの明確さ
# Test that error messages now indicate the effective limit source
node -e "
const { MediaStore, MediaLimitError } = require('openclaw/dist/store-CA7OW_2w');
const store = new MediaStore({ config: { media: { stagingMaxBytes: 1000000 } } });
const buffer = Buffer.alloc(2000000); // 2MB
try {
store.validateSize(buffer);
} catch (err) {
console.log('Error message:', err.message);
// Expected: includes both size and effective limit
// Should NOT just say 'Media exceeds 5MB limit'
}
"
# Expected: Error includes resolved effective limit, not hardcoded 5MB⚠️ よくある落とし穴
環境固有のトラップ
- Docker/コンテナデプロイメント —
dist/store-CA7OW_2w.js内のバンドルされたランタイムはコンテナイメージに埋め込まれています。実行中のコンテナ内でnode_modulesを変更しても、再起動後に持続しません。常にイメージをリビルドするか、設定オーバーライドをマウントしてください。# Incorrect - changes lost after container restart docker exec openclaw-container sed -i 's/5 \* 1024 \* 1024/50 * 1024 * 1024/g' /usr/local/lib/node_modules/openclaw/dist/store-CA7OW_2w.jsCorrect - use environment variables or volume mounts
docker run -e OPENCLAW_MEDIA_STAGING_MAX_BYTES=52428800 openclaw/app
- npmグローバルインストール vs ローカルインストール — バンドルの場所は異なります:
間違った場所をパッチ当てると、修正が有効に見えない原因になります。# Global install location $(npm root -g)/openclaw/dist/store-CA7OW_2w.jsLocal install location
./node_modules/openclaw/dist/store-CA7OW_2w.js
- モノレポ/ワークスペース設定 — OpenClawがワークスペースルートにインストールされている場合、ネストされたパッケージは異なるバンドルインスタンスを解決する可能性があります。すべてのパッケージが同じOpenClawインストールを参照していることを確認してください。
# Check bundle resolution node -e "console.log(require.resolve('openclaw/dist/store-CA7OW_2w.js'))"
設定のエッジケース
- ゼロまたはNullの上限値 — 修正は正でない値をフィルタリングする必要があります:
# This should NOT be treated as unlimited channels: slack: media: maxBytes: 0 # Disables limit? Or error?Verify your fix handles this correctly
openclaw config validate
Should warn about invalid zero/null media limits
- チャンネル固有の上限 vs グローバルデフォルト — 通常、すべての下限の最小値が正しい実効上限ですが、一部のワークフローでは最大値を意図している場合があります。選択したセマンティクスを明確に文書化してください。
- レガシー設定ファイル — 古い
.openclawrcJSONファイルはmedia.maxBytesの代わりにmediaMaxBytesを使用している場合があります。下位互換性を確認してください。
ランタイム動作の落とし穴
- 更新後のバンドルキャッシュ — OpenClawを更新した後、モジュールキャッシュをクリアします:
# Clear require cache in Node.js delete require.cache[require.resolve('openclaw/dist/store-CA7OW_2w.js')]Or restart the Node.js process entirely
- バッファリングされていないストリーミングメディア — メディアがストリーミングされる場合(例:ビデオ生成)、サイズ検証は最初にストリーム全体を読み取る必要がある場合があります。修正がバッファリングされたシナリオとストリーミングされたシナリオの両方を処理することを確認してください。
- 大きな上限でのメモリ压力 — 対応するメモリ設定なしにステージング上限を非常に高く設定すると(例:500MB以上)、ステージング操作中にOOMエラーが発生する可能性があります。
検証の失敗
検証テストが予期せず失敗した場合:
- バンドルが実際に更新されたことを確認する(
md5sum dist/store-CA7OW_2w.js) - モジュール解決パス内に複数のOpenClawインストールがあるか確認する
- 環境変数が正しく読み込まれていることを確認する(
console.log(process.env.OPENCLAW_MEDIA_STAGING_MAX_BYTES)) - プロセスが更新されたバンドルファイルを読み取る権限を持っていることを確認する
🔗 関連するエラー
以下のエラーと問題は、ハードコードされた5MBステージング上限と文脈的に関連しています:
MediaLimitError— メディアがステージングのしきい値を超えるときにスローされる主たるエラークラス。「Media exceeds 5MB limit」または修正後では「Media exceeds {effectiveLimit} bytes」として表示される場合があります。MEDIA_EXCEEDS_CHANNEL_LIMIT— ステージング後、メディアがチャンネル固有の制限を引き続き超えている場合に発生する下流エラー。このエラーは、ステージング上限がチャンネル設定から適切に導出されていれば発生しません。ENFILE/EMFILE(ファイルディスクリプタ制限) — 直接的には関連ありませんが、大きなメディアファイルが適切にストリーミングされない場合に表面化する場合があります。サイズ上限エラーと混同されやすいものです。EBADMSG(メッセージを処理できない) — メディア検証がサイズ制約により完全に解析する前に部分的に失敗した場合に発生する場合があります。5MBの制限により、不完全なメディアオブジェクトが下流に渡される可能性があります。- 問題: メディアメタデータのサイレントトリミング — メディアメタデータがステージング上限に近づいたときに剥离され、曖昧なエラーメッセージで下流の配信が失敗する関連する上位の問題。
- 問題: ~15秒以上のビデオ生成が失敗する — ユーザーは長い継続時間のビデオ生成が失敗すると報告しています。おそらくビデオが完全にアセンブリされる前に、蓄積されたフレームデータが5MBのステージング上限を超えているためです。
- 問題: メタデータが剥离されたオーディオファイル — メディアステージングの動作に関連し、高ビットレートのオーディオファイルが部分的に処理され、サイズ検証が厳格なときにID3/メタデータタグが失われます。
Upload payload too large— ダウンストリーム統合(Slack、Discordなど)からのチャンネル固有のエラーで、チャンネルの実際の制限を超えたことを示します。ステージングの修正後にこのエラーが表示された場合、チャンネル自体の上限を調整する必要があります。BufferOverflowError(カスタム) — 対応するバッファサイズ調整なしにステージングレイヤーが拡張された場合に、カスタムのOpenClawデプロイに表示される場合があります。- 歴史的:
dist/store.jsがdist/store-CA7OW_2w.jsに名前変更 — バンドルファイル名がバージョン間で変更されました。ドキュメントがインストールバージョンの正しい現在のバンドル名を参照していることを確認してください。
交差参照マトリックス
| エラー/問題 | レイヤー | 上限ソース | ステージングをオーバーライド可能? |
|---|---|---|---|
| Media exceeds 5MB limit | Staging (bundled) | Hardcoded constant | No (requires fix) |
| MEDIA_EXCEEDS_CHANNEL_LIMIT | Channel delivery | channel.media.maxBytes | Yes (config) |
| Upload payload too large | External API | Platform limit | No |
| BufferOverflowError | Custom/Extended | Custom implementation | Depends |