Skip to main content
fal limits how often you can call the operations that list, inspect, shell into, and stop your apps and runners. These limits protect the shared control plane. They do not apply to the requests that call your app endpoints.

Limits

Each limit is a number of calls in a one-minute window. fal counts the calls from each client separately. When the window resets, you can make calls again. The SDK methods belong to SyncServerlessClient. A CLI command and its SDK method use the same limit. For example, fal runners list and client.runners.list() count toward one limit of 120 calls per minute. fal runners logs gets the runner details one time before it shows logs. This call counts toward the GET /runners/{runner_id} limit in the REST API. These REST API endpoints also have limits:

When You Exceed a Limit

fal rejects the call until the window resets. The error depends on the interface:
  • REST API. The response has the status 429 Too Many Requests.
  • CLI and Python SDK. The call fails with the gRPC status RESOURCE_EXHAUSTED.
Both responses include the x-ratelimit-reset header. Its value is the number of seconds until the window resets. For gRPC calls, read this header from the trailing metadata. The CLI and the SDK do not retry a rejected call. Make sure that your code checks for this error and tries the call again.
If fal rejects a stop or kill call, the runner continues to run.

Stay Under the Limits

  • Wait between calls when you poll. For example, call client.apps.runners() every few seconds, not in a loop with no delay.
  • Use one list call, not one call for each runner. client.apps.runners("my-app") returns all runners of an app in one call.
  • Spread large batches of stop or kill calls over time.
  • After a rejected call, wait for the time in x-ratelimit-reset, and then try again.
This example kills a list of runners. When fal rejects a call, it waits for the window to reset and tries the call again: