Skip to content

fix: Recognize Actor memory and concurrent-run limit errors #1592

Open

Description

@jirispilka

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 sends actor-memory-limit-exceeded;
  • concurrent runs: the code checks cannot-start-actor-runs; the platform sends concurrent-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: isMemoryQuotaError compares type with the memory constant.
  • src/utils/apify_errors.ts:51: isActorRunLimitError compares type with the Standby constant. If that fails, it looks for the same string in the message (the HTTP 500 wrapper is a plain Error). Its docstring (:44-50) wrongly says a direct run reports cannot-start-actor-runs.
  • Consumers of isActorRunLimitError:
    • call_actor.ts:245;
    • utils/mcp.ts:310;
    • tool_status.ts:78 and :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_EXCEEDED to actor-memory-limit-exceeded.
  • Add a constant for concurrent-runs-limit-exceeded next to the existing one. In isActorRunLimitError, match type against both. Keep the message-substring fallback for cannot-start-actor-runs only.
  • Correct the isActorRunLimitError docstring: direct runs use concurrent-runs-limit-exceeded, and the Standby controller uses cannot-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-actor receiving actor-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-actor and direct Actor tools receiving concurrent-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-runs in an HTTP 500 wrapper still gets the concurrent-run message. It is classified SOFT_FAIL / INVALID_INPUT and logged through the existing client/billing path, and the HTTP status is kept where it is already recorded.
  • A concurrent-runs-limit-exceeded 402 is excluded from isX402PaymentRequiredError. A genuine payment-required control still matches.
  • Cover classifier decisions in utils.apify_errors and payment exclusion in utils.payment_errors. Update affected tests in tools.call_actor_common, utils.logging, utils.tool_status, and utils.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

  1. changed the title [-]fix: Memory and concurrent-run limit errors use the wrong API error types[/-] [+]fix: Recognize Actor memory and concurrent-run limit errors[/+] on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    t-aiIssues owned by the AI team.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions