[GH-ISSUE #6053] [Bug] EVM input-size refusal is reported as invalid_request without resource limits #3699

Closed
opened 2026-10-31 00:43:10 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 21, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6053

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

The shared EVM inspection service reports a fixed input-size refusal as invalid_request / invalid_input, with input-schema recovery and an out_of_range issue against path. It does not provide structured resource-limit details. The 4 MiB allowance survives only inside the issue message.

I executed the production service/provider boundary against a real 4,194,305-byte regular raw carrier. The refusal occurred before worker runtime creation. Linux host admission facts were simulated on macOS using the existing EVM test pattern; the file and its size check were real. No EVMole worker or util-linux command executed.

Reproduction

With the source checkout and its locked dependencies prepared, save the following as tests/process-global/evmInputLimit.test.ts, then run:

node node_modules/vitest/vitest.mjs run tests/process-global/evmInputLimit.test.ts --maxWorkers 1

This exact input-only body passed in a focused run. Assertions characterize the current incorrect classification. The Node executable satisfies only the executable regular-file admission check; the test asserts that no worker runtime starts. Process host descriptors are restored and the fixture is removed.

import { expect, it, vi } from "vitest";
import { EvmoleInterfaceProvider } from "../../src/evm/EvmoleInterfaceProvider.js";
import { EvmInterfaceService } from "../../src/application/evm/EvmInterfaceService.js";
import { projectAnalysisError } from "../../src/domain/analysisErrorProjection.js";
import { createTestWorkspace, removeTestWorkspace } from "../support/workspace/workspaceFixture.js";

vi.mock("node:fs/promises", async (importOriginal) => {
  const fs = await importOriginal<typeof import("node:fs/promises")>();
  return {
    ...fs,
    readFile: async (...args: Parameters<typeof fs.readFile>) =>
      args[0] === "/proc/self/limits"
        ? ["Max address space unlimited unlimited bytes",
           "Max cpu time unlimited unlimited seconds",
           "Max file size unlimited unlimited bytes"].join("\n")
        : fs.readFile(...args),
  };
});

it("reports an oversized EVM carrier as invalid input", async () => {
  const platform = Object.getOwnPropertyDescriptor(process, "platform")!;
  const arch = Object.getOwnPropertyDescriptor(process, "arch")!;
  const workspace = await createTestWorkspace("rea-evm-input-limit-");
  const path = await workspace.write("selected.bin", Buffer.alloc(4194305, 0));
  const createRuntime = vi.fn(async () => { throw new Error("Worker must not start"); });
  const provider = new EvmoleInterfaceProvider(
    {...workspace.environment, REA_EVM_PRLIMIT_COMMAND: process.execPath},
    undefined,
    createRuntime,
  );
  try {
    Object.defineProperty(process, "platform", {...platform, value: "linux"});
    Object.defineProperty(process, "arch", {...arch, value: "x64"});
    const result = await new EvmInterfaceService(provider).inspect({path, encoding: "raw"});
    if (result.ok) throw new Error("Expected size refusal");
    const projected = projectAnalysisError(result.error);
    expect(projected).toMatchObject({
      code: "invalid_request", category: "invalid_input", retryable: false,
      recovery: {kind: "inspect_input_contract", operation: "inspect_evm_interface"},
      details: {issues: [{path: ["path"], reason: "out_of_range"}]},
    });
    expect(projected.details?.reported_limits).toBeUndefined();
    expect(projected.details?.issues[0].message).toContain("4194304");
    expect(createRuntime).not.toHaveBeenCalled();
    expect(result.error.cleanupIncomplete).toBe(false);
    console.log(JSON.stringify(projected).replaceAll(path, "<carrier>"));
  } finally {
    Object.defineProperty(process, "platform", platform);
    Object.defineProperty(process, "arch", arch);
    await provider.close();
    await removeTestWorkspace(workspace.root);
  }
});

The size case also passed in an earlier three-case run alongside injected reply-limit and malformed-reply controls. Public EVM CLI/MCP transport, real Linux admission and actual EVMole inference were not executed.

Expected behavior

Keep refusing inputs above the fixed allowance. Represent this measured input file-size constraint as resource_constraint / resource_constraint, with resource: "file-size", maximum_input_bytes: 4194304, retryable: false, and recovery explaining the input allowance. Schema/usage discovery cannot raise that allowance.

The EVM guide documents the 4 MiB input bound separately from worker output and diagnostics. The error algebra distinguishes bounded resource admission from malformed input. The WABT translator already maps the identical stable-reader limit / file-size refusal to a resource constraint with structured input limits and input-specific recovery.

Impact and scope

P2: callers branching on the public code, category or recovery kind cannot identify this resource refusal consistently without interpreting message text. The observed result instead directs them to the input schema or CLI usage. Rejection and non-retryability remain effective; no incorrect successful result, input corruption or security-boundary crossing was observed.

The input case reproduced twice: once in the grouped run and once as the extracted single-case test. The retained size message supplies a manual workaround for recognizing the refusal. Selecting a suitable complete artifact within the allowance may permit a different analysis; truncating required bytes would not preserve this analysis. Natural workload frequency and actual downstream automation effects are unknown.

Both CLI and MCP call the executed service by source inspection; neither adapter was exercised for this report.

REA version

rea-agents 6.7.0; source revision 52415975942a4b9c53a817915b313ccc404f280e.

Runtime and platform

macOS 27.0.1 arm64; Node.js v26.12.0; locked Vitest 5.0.3. This supported Node runtime differs from the repository's exact Node 24.18.0 development pin, which was not separately exercised. Linux x64 platform/architecture and inherited-limit text were simulated.

Target and artifact context

A generated regular file containing 4,194,305 zero bytes, selected with encoding: "raw". Raw zero bytes form a valid carrier representation; no inference or chain interaction was attempted. Size admission occurs before carrier decoding.

Interface

Other

Earliest failure stage

Setup or provider admission

Relevant output or evidence

Actual canonical projection from the input-only run, with only the generated carrier path replaced by <carrier>:

{
  "code": "invalid_request",
  "category": "invalid_input",
  "message": "Analysis input is invalid. Check the arguments and try again.",
  "retryable": false,
  "remediation": {
    "action": "Read the declared input schema or CLI usage for inspect_evm_interface; if using MCP and the catalog may be stale, call tools/list. Correct the listed fields, then retry. Do not repeat the unchanged call."
  },
  "recovery": {
    "kind": "inspect_input_contract",
    "operation": "inspect_evm_interface"
  },
  "details": {
    "operation": "inspect_evm_interface",
    "issues": [{
      "path": ["path"],
      "reason": "out_of_range",
      "message": "Selected artifact exceeds 4194304 bytes: <carrier>"
    }]
  }
}

The test also confirmed details.reported_limits was absent, createRuntime was never called, and cleanupIncomplete was false. The focused run completed with one test passed.

Typed outcome or recovery expected

Preserve refusal and retryable: false. Return resource_constraint, details.resource: "file-size", and details.reported_limits.maximum_input_bytes: 4194304. Explain that the fixed input allowance cannot be increased through schema discovery, delivery mode, or reply-size settings. Do not suggest truncating required content. Retain distinct input errors for malformed paths or carrier representations.

Analysis or suspected cause

Source-derived: the provider read uses the fixed input constant. The stable reader throws ArtifactReaderFailure("limit", ..., {boundary: "file-size"}). The EVM failure translator groups limit with path and format, then constructs AnalysisInputError. The service returns that provider error unchanged.

Handle the measured input-byte allowance at this producing boundary, retaining cleanup information and the existing limit. No limit increase or change to target execution is requested.

Additional context

Related #5848 covers the complete-reply allowance after worker execution, at a different translation branch. #4621 covered WASM's input-size classification; its corrected translator supplies the comparison above. #5405 concerns Rust/IL2CPP recovery wording with an already-correct resource classification. #6035 concerns retryability of native matching's separate representation allowance. Broad recovery tracker #5808 does not report this concrete EVM input-admission branch.

Fetched upstream main at 6d356b84344659085f2b912857b5e27fe0160c9b. The relevant input constant, reader, provider, service, failure translator and error classification are unchanged. Upstream changes to resource-parser test assertions and an optional captured-output projection helper do not repair this refusal. The later revision was inspected, not executed. No last-known-good release or regression range was established.

Originally created by @coygeek on GitHub (Oct 21, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6053 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior The shared EVM inspection service reports a fixed input-size refusal as `invalid_request` / `invalid_input`, with input-schema recovery and an `out_of_range` issue against `path`. It does not provide structured resource-limit details. The 4 MiB allowance survives only inside the issue message. I executed the production service/provider boundary against a real 4,194,305-byte regular raw carrier. The refusal occurred before worker runtime creation. Linux host admission facts were simulated on macOS using the existing EVM test pattern; the file and its size check were real. No EVMole worker or util-linux command executed. ### Reproduction With the source checkout and its locked dependencies prepared, save the following as `tests/process-global/evmInputLimit.test.ts`, then run: ```sh node node_modules/vitest/vitest.mjs run tests/process-global/evmInputLimit.test.ts --maxWorkers 1 ``` This exact input-only body passed in a focused run. Assertions characterize the current incorrect classification. The Node executable satisfies only the executable regular-file admission check; the test asserts that no worker runtime starts. Process host descriptors are restored and the fixture is removed. ```ts import { expect, it, vi } from "vitest"; import { EvmoleInterfaceProvider } from "../../src/evm/EvmoleInterfaceProvider.js"; import { EvmInterfaceService } from "../../src/application/evm/EvmInterfaceService.js"; import { projectAnalysisError } from "../../src/domain/analysisErrorProjection.js"; import { createTestWorkspace, removeTestWorkspace } from "../support/workspace/workspaceFixture.js"; vi.mock("node:fs/promises", async (importOriginal) => { const fs = await importOriginal<typeof import("node:fs/promises")>(); return { ...fs, readFile: async (...args: Parameters<typeof fs.readFile>) => args[0] === "/proc/self/limits" ? ["Max address space unlimited unlimited bytes", "Max cpu time unlimited unlimited seconds", "Max file size unlimited unlimited bytes"].join("\n") : fs.readFile(...args), }; }); it("reports an oversized EVM carrier as invalid input", async () => { const platform = Object.getOwnPropertyDescriptor(process, "platform")!; const arch = Object.getOwnPropertyDescriptor(process, "arch")!; const workspace = await createTestWorkspace("rea-evm-input-limit-"); const path = await workspace.write("selected.bin", Buffer.alloc(4194305, 0)); const createRuntime = vi.fn(async () => { throw new Error("Worker must not start"); }); const provider = new EvmoleInterfaceProvider( {...workspace.environment, REA_EVM_PRLIMIT_COMMAND: process.execPath}, undefined, createRuntime, ); try { Object.defineProperty(process, "platform", {...platform, value: "linux"}); Object.defineProperty(process, "arch", {...arch, value: "x64"}); const result = await new EvmInterfaceService(provider).inspect({path, encoding: "raw"}); if (result.ok) throw new Error("Expected size refusal"); const projected = projectAnalysisError(result.error); expect(projected).toMatchObject({ code: "invalid_request", category: "invalid_input", retryable: false, recovery: {kind: "inspect_input_contract", operation: "inspect_evm_interface"}, details: {issues: [{path: ["path"], reason: "out_of_range"}]}, }); expect(projected.details?.reported_limits).toBeUndefined(); expect(projected.details?.issues[0].message).toContain("4194304"); expect(createRuntime).not.toHaveBeenCalled(); expect(result.error.cleanupIncomplete).toBe(false); console.log(JSON.stringify(projected).replaceAll(path, "<carrier>")); } finally { Object.defineProperty(process, "platform", platform); Object.defineProperty(process, "arch", arch); await provider.close(); await removeTestWorkspace(workspace.root); } }); ``` The size case also passed in an earlier three-case run alongside injected reply-limit and malformed-reply controls. Public EVM CLI/MCP transport, real Linux admission and actual EVMole inference were not executed. ### Expected behavior Keep refusing inputs above the fixed allowance. Represent this measured input file-size constraint as `resource_constraint` / `resource_constraint`, with `resource: "file-size"`, `maximum_input_bytes: 4194304`, `retryable: false`, and recovery explaining the input allowance. Schema/usage discovery cannot raise that allowance. The [EVM guide](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/docs/evm-bytecode.md#L105-L122) documents the 4 MiB input bound separately from worker output and diagnostics. The [error algebra](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/domain/analysisErrorCore.ts#L23-L55) distinguishes bounded resource admission from malformed input. The [WABT translator](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/wasm/WabtFailures.ts#L215-L233) already maps the identical stable-reader `limit` / `file-size` refusal to a resource constraint with structured input limits and input-specific recovery. ### Impact and scope P2: callers branching on the public code, category or recovery kind cannot identify this resource refusal consistently without interpreting message text. The observed result instead directs them to the input schema or CLI usage. Rejection and non-retryability remain effective; no incorrect successful result, input corruption or security-boundary crossing was observed. The input case reproduced twice: once in the grouped run and once as the extracted single-case test. The retained size message supplies a manual workaround for recognizing the refusal. Selecting a suitable complete artifact within the allowance may permit a different analysis; truncating required bytes would not preserve this analysis. Natural workload frequency and actual downstream automation effects are unknown. Both [CLI](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/cli/evmCommands.ts#L16-L40) and [MCP](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/server/registerEvmTools.ts#L30-L50) call the executed service by source inspection; neither adapter was exercised for this report. ### REA version `rea-agents` 6.7.0; source revision `52415975942a4b9c53a817915b313ccc404f280e`. ### Runtime and platform macOS 27.0.1 arm64; Node.js v26.12.0; locked Vitest 5.0.3. This supported Node runtime differs from the repository's exact Node 24.18.0 development pin, which was not separately exercised. Linux x64 platform/architecture and inherited-limit text were simulated. ### Target and artifact context A generated regular file containing 4,194,305 zero bytes, selected with `encoding: "raw"`. Raw zero bytes form a valid carrier representation; no inference or chain interaction was attempted. Size admission occurs before carrier decoding. ### Interface Other ### Earliest failure stage Setup or provider admission ### Relevant output or evidence Actual canonical projection from the input-only run, with only the generated carrier path replaced by `<carrier>`: ```json { "code": "invalid_request", "category": "invalid_input", "message": "Analysis input is invalid. Check the arguments and try again.", "retryable": false, "remediation": { "action": "Read the declared input schema or CLI usage for inspect_evm_interface; if using MCP and the catalog may be stale, call tools/list. Correct the listed fields, then retry. Do not repeat the unchanged call." }, "recovery": { "kind": "inspect_input_contract", "operation": "inspect_evm_interface" }, "details": { "operation": "inspect_evm_interface", "issues": [{ "path": ["path"], "reason": "out_of_range", "message": "Selected artifact exceeds 4194304 bytes: <carrier>" }] } } ``` The test also confirmed `details.reported_limits` was absent, `createRuntime` was never called, and `cleanupIncomplete` was false. The focused run completed with one test passed. ### Typed outcome or recovery expected Preserve refusal and `retryable: false`. Return `resource_constraint`, `details.resource: "file-size"`, and `details.reported_limits.maximum_input_bytes: 4194304`. Explain that the fixed input allowance cannot be increased through schema discovery, delivery mode, or reply-size settings. Do not suggest truncating required content. Retain distinct input errors for malformed paths or carrier representations. ### Analysis or suspected cause Source-derived: the [provider read](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/evm/EvmoleInterfaceProvider.ts#L466-L473) uses the fixed input constant. The [stable reader](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/artifacts/readStableArtifact.ts#L65-L70) throws `ArtifactReaderFailure("limit", ..., {boundary: "file-size"})`. The [EVM failure translator](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/evm/EvmoleFailures.ts#L145-L160) groups `limit` with `path` and `format`, then constructs `AnalysisInputError`. The [service](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/application/evm/EvmInterfaceService.ts#L50-L61) returns that provider error unchanged. Handle the measured input-byte allowance at this producing boundary, retaining cleanup information and the existing limit. No limit increase or change to target execution is requested. ### Additional context Related [#5848](https://github.com/morluto/rea/issues/5848) covers the complete-reply allowance after worker execution, at a different translation branch. [#4621](https://github.com/morluto/rea/issues/4621) covered WASM's input-size classification; its corrected translator supplies the comparison above. [#5405](https://github.com/morluto/rea/issues/5405) concerns Rust/IL2CPP recovery wording with an already-correct resource classification. [#6035](https://github.com/morluto/rea/issues/6035) concerns retryability of native matching's separate representation allowance. Broad recovery tracker [#5808](https://github.com/morluto/rea/issues/5808) does not report this concrete EVM input-admission branch. Fetched upstream main at `6d356b84344659085f2b912857b5e27fe0160c9b`. The relevant input constant, reader, provider, service, failure translator and error classification are unchanged. Upstream changes to resource-parser test assertions and an optional captured-output projection helper do not repair this refusal. The later revision was inspected, not executed. No last-known-good release or regression range was established.
Author
Owner

@Bilalmesk commented on GitHub (Oct 22, 2026):

Draft PR #6414 implements this at the EVM failure-translation boundary: the artifact-read limit/file-size reader refusal now maps to a non-retryable resource_constraint with resource: "file-size" and reported_limits.maximum_input_bytes: 4194304, following the WABT input translator; path/format reader refusals keep their input-error projection. Translator-level regression coverage fails on the affected base and passes with the fix. Real Linux admission and CLI/MCP transport coverage were not run locally (Windows source checkout); the PR stays draft pending the human owner's review and readiness declarations.

<!-- gh-comment-id:6353175688 --> @Bilalmesk commented on GitHub (Oct 22, 2026): Draft PR #6414 implements this at the EVM failure-translation boundary: the artifact-read `limit`/`file-size` reader refusal now maps to a non-retryable `resource_constraint` with `resource: "file-size"` and `reported_limits.maximum_input_bytes: 4194304`, following the WABT input translator; `path`/`format` reader refusals keep their input-error projection. Translator-level regression coverage fails on the affected base and passes with the fix. Real Linux admission and CLI/MCP transport coverage were not run locally (Windows source checkout); the PR stays draft pending the human owner's review and readiness declarations.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3699
No description provided.