ComposioHQ/composio · error · Error
proxy fetch only supports GET, POST, PUT, DELETE, PATCH.
Error message
proxy fetch only supports GET, POST, PUT, DELETE, PATCH.
What it means
The proxy fetch layer only forwards GET, POST, PUT, DELETE, and PATCH (after uppercasing init.method; default GET). normalizeFetchInput rejects any other HTTP verb such as HEAD, OPTIONS, or custom methods.
Source
Thrown at ts/packages/cli/src/services/run-helpers-runtime.ts:433
if (ArrayBuffer.isView(body)) {
return encodeBase64(new Uint8Array(body.buffer, body.byteOffset, body.byteLength));
}
return body;
};
const normalizeFetchInput = async (input: unknown, init: RequestInit = {}) => {
if (typeof Request !== 'undefined' && input instanceof Request) {
throw new Error(
'proxy() does not support passing a Request instance yet. Pass a URL string and init instead.'
);
}
const endpoint = input instanceof URL ? input.toString() : input;
if (typeof endpoint !== 'string' || endpoint.trim().length === 0) {
throw new Error('proxy fetch requires a non-empty URL string or URL object.');
}
const method = typeof init.method === 'string' ? init.method.toUpperCase() : 'GET';
if (!['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(method)) {
throw new Error('proxy fetch only supports GET, POST, PUT, DELETE, PATCH.');
}
return {
endpoint: endpoint.trim(),
method,
parameters: normalizeFetchHeaders(init.headers),
body: await normalizeFetchBody(init.body),
};
};
const toProxyResponse = async (result: ProxyExecuteResponse) => {
const headers = new Headers(result?.headers || {});
if (result?.binary_data?.url) {
const binaryResponse = await fetch(result.binary_data.url);
binaryResponse.headers.forEach((value, key) => {
if (!headers.has(key)) headers.set(key, value);
});
return new Response(binaryResponse.body, {
status: result.status ?? binaryResponse.status,View on GitHub (pinned to 64b1b85502)
Solutions
- Use one of GET/POST/PUT/DELETE/PATCH (case-insensitive)
- For HEAD, issue a GET and ignore the body, or use a direct fetch outside the proxy
- Validate the method against the allowlist before calling proxy.fetch when it comes from user input
Example fix
// before
await proxy.fetch(url, { method: 'HEAD' });
// after
await proxy.fetch(url, { method: 'GET' }); // ignore response body if unneeded Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED = ['GET','POST','PUT','DELETE','PATCH'];
if (!ALLOWED.includes((method ?? 'GET').toUpperCase())) throw new RangeError(`method must be one of ${ALLOWED.join(',')}`); Type guard
const isAllowedMethod = (m: string): m is 'GET'|'POST'|'PUT'|'DELETE'|'PATCH' => ['GET','POST','PUT','DELETE','PATCH'].includes(m.toUpperCase());
Prevention
- Uppercase methods by convention
- Avoid HEAD/OPTIONS through the proxy; use direct fetch
When it happens
Trigger: Calling proxy.fetch(url, { method: 'HEAD' }), { method: 'OPTIONS' }, or a lowercased verb that is still unsupported ('trace', 'connect').
Common situations: Health checks using HEAD, CORS preflight emulation with OPTIONS, or generic fetch wrappers that pass through arbitrary caller-supplied methods.
Related errors
- proxy fetch requires a non-empty URL string or URL object.
- proxy_execute: toolkit is required
- proxy_execute: endpoint is required
- proxy_execute: method must be one of {sorted(_VALID_METHODS)
- proxy() requires a non-empty toolkit string.
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/d47a728475058c5e.
Report an issue: GitHub.