fix(http): resolve 5-minute timeout limit for API block requests
Summary
This PR fixes the root cause of issue #2242 where API block requests timeout at 5 minutes regardless of user-configured timeout settings.
Root Cause
Bun/Node.js fetch has a hardcoded 5-minute (300 seconds) default timeout that cannot be overridden by AbortSignal.timeout(). This is documented in Bun PR #6217.
Solution
- Add
timeout: falseto all fetch calls to disable Bun/Node.js default 5-minute timeout - Use
AbortSignal.timeout()for user-configurable timeout control (default: 2 min, max: 10 min) - Add
maxDuration = 600to/api/proxyand/api/workflows/[id]/executeroutes for Next.js
Changes
| File | Changes |
|---|---|
apps/sim/tools/index.ts |
Add parseTimeout() function, add timeout: false + AbortSignal.timeout() to handleInternalRequest and handleProxyRequest |
apps/sim/app/api/proxy/route.ts |
Add maxDuration = 600 and timeout: false |
apps/sim/app/api/workflows/[id]/execute/route.ts |
Add maxDuration = 600 |
apps/sim/tools/http/types.ts |
Add timeout?: number field to RequestParams |
Test Results
| Scenario | Result |
|---|---|
Without timeout: false + 6-min request |
❌ Timeout at 5 minutes |
With timeout: false + 6-min request |
✅ Completed successfully after 6 minutes |
Test Plan
- [x] Verified 6-minute API request completes successfully with
timeout: false - [ ] Test in Sim.AI UI with API block configured for 10-minute timeout
- [ ] Verify Docker deployment works with long-running requests
Closes #2242
🤖 Generated with Claude Code
@majiayu000 is attempting to deploy a commit to the Sim Team on Vercel.
A member of the Team first needs to authorize it.
Greptile Summary
Fixed the 5-minute timeout limit for API block requests by disabling Bun/Node.js default timeout and implementing user-configurable timeout control (2-10 minutes).
Key Changes:
- Added
parseTimeout()function to validate and clamp timeout values between 2-10 minutes - Applied
timeout: false+AbortSignal.timeout()tohandleInternalRequestandhandleProxyRequestintools/index.ts - Added
maxDuration = 600to/api/proxyand/api/workflows/[id]/executeroutes for Next.js - Added
timeoutfield toRequestParamstype definition
Issues Found:
- GET handler in
/api/proxy/route.tssetstimeout: falsebut doesn't includeAbortSignal.timeout(), creating inconsistent timeout behavior between GET and POST handlers
Confidence Score: 4/5
- This PR is safe to merge with one logical fix needed for the GET handler
- The core timeout fix is well-implemented with proper validation and documentation. However, the GET handler in
apps/sim/app/api/proxy/route.tsis missingAbortSignal.timeout(), which creates inconsistent behavior - it has no timeout control except the route'smaxDuration. This should be fixed to match the POST handlers' pattern of using bothtimeout: falseandsignal: AbortSignal.timeout(). -
apps/sim/app/api/proxy/route.tsGET handler needsAbortSignal.timeout()added for consistent timeout behavior
Important Files Changed
| Filename | Overview |
|---|---|
| apps/sim/tools/index.ts | Added parseTimeout() function and timeout handling with timeout: false + AbortSignal.timeout() to both request handlers |
| apps/sim/app/api/proxy/route.ts | Added maxDuration = 600 and timeout: false to GET handler, but missing AbortSignal for timeout control |
Sequence Diagram
sequenceDiagram
participant Client as API Block/Client
participant ProxyRoute as /api/proxy
participant ToolHandler as tools/index.ts
participant ExternalAPI as External API
Note over Client,ExternalAPI: User-configured timeout flow
Client->>ProxyRoute: POST /api/proxy<br/>{toolId, params: {timeout: 600000}}
Note over ProxyRoute: maxDuration = 600s<br/>(Next.js route config)
ProxyRoute->>ToolHandler: executeTool(toolId, params)
alt Internal Request Handler
ToolHandler->>ToolHandler: parseTimeout(params.timeout)<br/>Returns: min(timeout, 600000ms)
Note over ToolHandler: timeout: false<br/>signal: AbortSignal.timeout(timeoutMs)
ToolHandler->>ExternalAPI: fetch(url, {timeout: false, signal})
ExternalAPI-->>ToolHandler: Response (within timeout)
ToolHandler-->>ProxyRoute: Success
else Proxy Request Handler
ToolHandler->>ToolHandler: parseTimeout(params.timeout)<br/>Returns: min(timeout, 600000ms)
Note over ToolHandler: timeout: false<br/>signal: AbortSignal.timeout(timeoutMs)
ToolHandler->>ProxyRoute: fetch(/api/proxy, {timeout: false, signal})
ProxyRoute->>ExternalAPI: Forward request
ExternalAPI-->>ProxyRoute: Response (within timeout)
ProxyRoute-->>ToolHandler: Response
ToolHandler-->>ProxyRoute: Success
end
ProxyRoute-->>Client: Response with result
Note over Client,ExternalAPI: Timeout scenarios
alt Timeout Exceeded
ToolHandler->>ExternalAPI: fetch with AbortSignal
Note over ExternalAPI: Request takes > timeoutMs
ExternalAPI-xToolHandler: AbortError (signal timeout)
ToolHandler-->>Client: Error: Request timed out
end
alt GET /api/proxy (Direct Proxy)
Client->>ProxyRoute: GET /api/proxy?url=...
Note over ProxyRoute: timeout: false<br/>NO AbortSignal!<br/>Relies only on maxDuration=600s
ProxyRoute->>ExternalAPI: fetch(url, {timeout: false})
ExternalAPI-->>ProxyRoute: Response
ProxyRoute-->>Client: Response
end