Repository navigation
Description
Problem
call-actor has dedicated messages for the account memory limit and the concurrent-run limit. Direct Actor tools share the concurrent-run matcher, but their memory-limit path is separate (see the scope note below). The checks compare the platform's error type against the wrong strings:
- memory: the code checks
memory-limit-exceeded; the platform sendsactor-memory-limit-exceeded; - concurrent runs: the code checks
cannot-start-actor-runs; the platform sendsconcurrent-runs-limit-exceeded.
Both checks miss. In call-actor, the response falls through to generic Actor-name/input hints. For direct Actor tools, the concurrent-run 402 is mistaken for an x402 payment request.
The original hosted observation: an account with a 16 GB memory quota requested 32768 MB for apify/web-fetch. The response reported the 16384 MB limit, followed by the generic Actor-name and input hints.
Decision: fix the memory type, match both concurrent-run types
cannot-start-actor-runs is a real error type, but from a different source. The Actor Standby controller wraps any failed run start as cannot-start-actor-runs, HTTP 500, with the original message appended (actor-standby-controller/src/errors.ts). This is how a remote MCP-server Actor surfaces the limit. Replacing the constant would break that path, so both types are matched.
Validation: confirmed on October 30, 2026
Checked against master f9f0ced. A local Node/tsx probe created ApifyApiError instances with the literal platform type strings and HTTP 402:
actor-memory-limit-exceeded: isMemoryQuotaError=false
concurrent-runs-limit-exceeded: isActorRunLimitError=false, isX402PaymentRequiredError=true
cannot-start-actor-runs: isActorRunLimitError=true, isX402PaymentRequiredError=false
This probe calls classifiers only; it starts no Actor runs. The hosted observation above is prior evidence, not a new hosted reproduction.
Platform types independently checked in apify-core/src/packages/errors/src/errors/actor.ts at 81c2700ed3951008ed30c9d1902991fc44a4f764; the Standby wrapper was checked in actor-standby-controller/src/errors.ts at 33cd4a24209266ba579f769313790a17da9e8cf8:
actor-memory-limit-exceeded, HTTP 402;concurrent-runs-limit-exceeded, HTTP 402.
Public code: matchers, call-actor handling, and payment-first mapper.
Code:
src/const.ts:295:APIFY_ERROR_TYPE_MEMORY_LIMIT_EXCEEDED = 'memory-limit-exceeded'. This is wrong.src/const.ts:296:APIFY_ERROR_TYPE_CANNOT_START_ACTOR_RUNS = 'cannot-start-actor-runs'. This is right for Standby, but misses direct runs.src/utils/apify_errors.ts:26:isMemoryQuotaErrorcomparestypewith the memory constant.src/utils/apify_errors.ts:51:isActorRunLimitErrorcomparestypewith the Standby constant. If that fails, it looks for the same string in the message (the HTTP 500 wrapper is a plainError). Its docstring (:44-50) wrongly says a direct run reportscannot-start-actor-runs.- Consumers of
isActorRunLimitError:call_actor.ts:245;utils/mcp.ts:310;tool_status.ts:78and:104;logging.ts:169;payment_errors.ts:19, which excludes the limit from x402 handling.apify_errors.ts:83.
Fix
- Change the value of
APIFY_ERROR_TYPE_MEMORY_LIMIT_EXCEEDEDtoactor-memory-limit-exceeded. - Add a constant for
concurrent-runs-limit-exceedednext to the existing one. InisActorRunLimitError, matchtypeagainst both. Keep the message-substring fallback forcannot-start-actor-runsonly. - Correct the
isActorRunLimitErrordocstring: direct runs useconcurrent-runs-limit-exceeded, and the Standby controller usescannot-start-actor-runs(HTTP 500). - Don't rename symbols or rewrite the dedicated messages. Every consumer goes through the two matchers, so the consumers need no change.
Acceptance
- Regression inputs use the literal type strings, not the constants under test.
-
call-actorreceivingactor-memory-limit-exceeded(402) gets the existing memory message, without the Actor-name or input hints. This assertion does not apply to the direct Actor tool payment-first mapper. - Both
call-actorand direct Actor tools receivingconcurrent-runs-limit-exceeded(402) get the concurrent-run message, without those hints or an x402 payment result. - A remote MCP-server error whose message carries
cannot-start-actor-runsin an HTTP 500 wrapper still gets the concurrent-run message. It is classifiedSOFT_FAIL / INVALID_INPUTand logged through the existing client/billing path, and the HTTP status is kept where it is already recorded. - A
concurrent-runs-limit-exceeded402 is excluded fromisX402PaymentRequiredError. A genuine payment-required control still matches. - Cover classifier decisions in
utils.apify_errorsand payment exclusion inutils.payment_errors. Update affected tests intools.call_actor_common,utils.logging,utils.tool_status, andutils.mcp; use a small wiring pair per consumer, not the same error-type matrix in every suite.
Write the regression first and confirm it fails before fixing the code. Follow AGENTS.md and tests/UNIT_TESTING_GUIDE.md, and run pnpm run type-check, pnpm run lint, pnpm run test:unit, pnpm run format, and pnpm run check:agents. Don't run integration tests, evals or paid Actor runs. Don't repeat the hosted reproduction: on a larger account the request can start a paid run.
Out of scope, confirmed by code inspection: isX402PaymentRequiredError does not exclude a memory-limit 402, and direct Actor tools reach the payment-first branch in tool_call_error_mapper.ts:60. This issue does not promise a dedicated memory message on that path. Report the remaining behavior in the PR; do not change payment handling for memory errors here. No hosted schema changes are required; flag the shared error-classification change for apify-mcp-server-internal.
AI assistance: Codex reproduced the local paths. Claude Code verified the platform and Standby error types and rewrote this issue for the decision above.
Codex validation: independently checked the public paths and upstream definitions and ran the local classifier probe above. No implementation changes or paid runs were made.
Implementation handoff
Implementation requires assignment or explicit maintainer approval under CONTRIBUTING.md; this validation does not assign the issue. Follow the root and relevant child AGENTS.md files, CONTRIBUTING.md, and TOOL_GUIDELINES.md. Keep one concern per PR, reuse existing helpers, and self-review the diff. Update any affected owning documentation in the same PR. Disclose AI assistance and include the issue link and reproduction evidence in the PR; leave the PR template's human-written reviewer section to the author.
Estimate
5 person-hours (Fibonacci estimate) of focused implementation effort for one engineer or an engineer supervising an independent agent. Rounded up to the next Fibonacci number from the previous range's upper bound. This is a planning estimate, not measured agent runtime or a delivery commitment.
Small constant/matcher changes, with regression coverage for classification, payment exclusion, and the existing call paths. No live quota reproduction or paid run is needed.
Includes familiarization, implementation, focused regression tests, the five required checks, relevant documentation, safe mcpc proof where called for, and PR preparation. Assumes a working environment and the issue's stated scope. Excludes review/CI queue time, human-only integration execution, internal-repository changes, and deployment. Any blocked verification must be recorded in the PR; the estimate does not waive required checks.
Activity
[-]fix: Memory and concurrent-run limit errors use the wrong API error types[/-][+]fix: Recognize Actor memory and concurrent-run limit errors[/+]