> Raw Markdown twin (generated at build time from the source Markdown). Rendered page: https://docs.gatellm.io/en/reference/scripting-config · Doc index: https://docs.gatellm.io/en/llms.txt


# Script runtime limits and configuration

This chapter covers the script engine's environment variables, limits and safety, and the script testing entry. For the API reference see [Scripting API reference](/en/reference/scripting-api.md); for an intro see [Write your first script transform](/en/howto/write-script-transform.md).

## Script-related environment variables

| Variable | Default | Purpose |
|------|--------|------|
| `SCRIPT_MAX_OPERATIONS` | `2000` | Maximum operations per script execution |
| `SCRIPT_MEMORY_LIMIT_MB` | `64` | Interpreter heap cap (MB) |
| `SCRIPT_LAZY_BODY` | `true` | Whether to lazily project the request/response body; `false` takes the legacy whole-materialization branch |

These three control the operation cap and memory; other resource limits (string size, array elements, stack size, etc.) are hardcoded by the sandbox and not configurable. Environment-variable changes require a container restart to take effect. The full env-var list is in [Environment variable reference](/en/reference/configuration.md).

## Resource limits

| Limit | Value | Configurable |
|------|------|--------|
| Max operations | 2,000 | `SCRIPT_MAX_OPERATIONS` |
| Interpreter heap cap | 64 MB | `SCRIPT_MEMORY_LIMIT_MB` (a runtime-creation-time constraint; changes require restart) |
| Concurrent execution slots | 4 | `server.script_pool_size` (a TOML field, not an env var; the number of scripts running concurrently, each slot's heap bounded by `SCRIPT_MEMORY_LIMIT_MB`) |
| body lazy projection | on | `SCRIPT_LAZY_BODY` (default `true`; `false` takes the legacy whole-materialization branch; rollback is by explicitly switching back; changes require restart) |
| Max string | 10 MB | fixed |
| Max array/object elements | 10,000 | fixed |
| Regex cache | 256 entries, 5-minute TTL | fixed |
| Stack size | 1024 frames | fixed |

> ℹ️ **body view semantics**: with `SCRIPT_LAZY_BODY=true`, `body` is a lazy-projection view that materializes on access; the whole body doesn't enter the JS heap, and JS heap usage only tracks the fields the script accesses. The view is consistent with a real object under standard checks like `Array.isArray` / `instanceof` / `typeof` / `Object.keys` / destructuring / spread / `JSON.stringify` / array methods. **Known boundary**: `body.x === body.x` is false (the shell isn't cached); scripts relying on same-path reference equality must compare by value instead.

## Sandbox limits

### What scripts can do

- Read and modify `body`
- Read `context` metadata
- Use all built-in functions (json_path, str_*, regex_*, array_*, etc.)
- Define helper functions
- Use standard JavaScript (loops, conditionals, closures, destructuring, etc.)

### What scripts cannot do

| Forbidden | Reason |
|--------|--------|
| `console.log` / `print` | Prevent information leakage |
| File I/O | No filesystem access |
| Network / `fetch` | No network access |
| `import` / `require` | Cannot load external code |
| `eval` / `Function` | Cannot dynamically execute code |
| `globalThis` mutation | The global object is frozen |

## Error handling

### script_error_mode

| Mode | Behavior | Use case |
|------|------|---------|
| `log-and-continue` (default) | On script error, logs a warn and continues the request with the original body | Script failure shouldn't block requests |
| `log-and-reject` | On script error, rejects the request and returns a gateway error | Script correctness is critical (e.g. security redaction) |

### Common errors

| Error | Cause | Fix |
|------|------|------|
| `transform() must return a value` | Some return path forgot to return body | **Every return must return body** |
| `TooManyOperations` | Exceeded the operation cap (default 2000) | Optimize loops |
| `TypeError` | Accessing a property of null/undefined | Check with `json_path()` or the `in` operator |
| `ReferenceError` | Using an undefined variable or function | Check spelling |

### Early returns must return body

```javascript
function transform(body, context) {
    // ✅ correct
    if (!body.messages) return body;

    // ❌ wrong: returning no value → the script silently fails
    if (!body.messages) return;

    body.messages[0].content = "modified";
    return body;
}
```

## Script testing {#script-testing}

Test scripts before deploying. The test endpoint `POST /console/api/scripts/test` needs console auth — pass it via the `$CONSOLE_TOKEN` environment variable (it is **not** the upstream access key; it's the console API credential). Get it either of two ways:

::: tip Getting CONSOLE_TOKEN
**Way 1: configure `CONSOLE_SECRET_KEY` (recommended for scripts / CI)** — set the `CONSOLE_SECRET_KEY` environment variable; the console uses it as a Bearer token, long-lived and never expires:

```bash
# inject at gateway startup
docker run -d -e CONSOLE_SECRET_KEY="my-secret-key-xxx" ... <image>

# pass it when testing scripts
export CONSOLE_TOKEN="my-secret-key-xxx"
```

**Way 2: log in with a console account to get a session token** — use this path when `CONSOLE_SECRET_KEY` isn't configured. `POST /console/api/login` logs in with account/password; the returned `token` field is the session token (valid 24 hours by default; calls slide-renew it):

```bash
export CONSOLE_TOKEN=$(curl -s http://localhost:7890/console/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"protoflux","password":"your-password"}' | jq -r .token)
```

`CONSOLE_SECRET_KEY` and the login password (`CONSOLE_PASSWORD`) are independent; you can configure only one. See [Console login and roles](/en/console/login-and-roles.md).
:::

```bash
curl -X POST http://localhost:7890/console/api/scripts/test \
  -H "Authorization: Bearer $CONSOLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "script": "function transform(body, context) { body.model = context.upstreamModel; return body; }",
    "body": {"model": "gpt-4o", "messages": []},
    "context": {
      "clientModel": "gpt-4o",
      "upstreamModel": "gpt-4o-2024-05-13",
      "upstreamName": "openai",
      "sourceProtocol": "OpenAIChatCompletions",
      "targetProtocol": "OpenAIChatCompletions",
      "stream": false
    }
  }'
```

Response:
```json
{
  "result_body": {"model": "gpt-4o-2024-05-13", "messages": []},
  "execution_time_ms": 0.12
}
```

## Performance advice

::: tip Performance and memory
Script overhead mainly comes from JSON serialization; latency grows linearly with the body. For the after-slot large-body OOM anti-pattern, latency references, and writing advice, see [Script performance and memory](/en/practices/script-performance.md).
:::

## FAQ

**Q: Where do I configure scripts in the console UI?**
Both the upstream detail page and the model detail page have "Request script" and "Response script" input boxes. You can also set them directly via the Console API.

**Q: The script changed body.model, but the route didn't change.**
`body.model` only changes the request body's field, not the route. To switch routes use `context.useModel("model-name")`.

**Q: Does a response script work for streaming requests?**
Streaming-response scripts are not supported yet. Request scripts work for streaming requests, but response scripts only take effect for non-streaming.

**Q: The script errored but the request passed normally?**
In the default `log-and-continue` mode, script errors don't block requests. Check the warn log for the error reason. If the script must succeed, switch to `log-and-reject`.

**Q: Why is there no Authorization in context.headers?**
Security design: sensitive headers like `authorization`, `cookie`, `x-api-key` are removed before scripts can see them, to prevent credential leakage.

**Q: How do I raise the operation cap?**
`SCRIPT_MAX_OPERATIONS` is tunable. But optimize the script first — `TooManyOperations` usually means loop complexity is too high.

**Next**: [Scripting API reference](/en/reference/scripting-api.md) for the full built-in function table; [Write your first script transform](/en/howto/write-script-transform.md) for the intro structure; [Environment variable reference](/en/reference/configuration.md) for all environment variables; [Audit and security configuration](/en/reference/audit-and-security-config.md) for other security settings.
