## TL;DR
Cloudflare Workers (the workerd runtime) only implements two fetch redirect modes: "follow" and "manual". If your code or a library passes `redirect: "error"`, workerd throws a TypeError synchronously, before any request is sent. Replace `"error"` with `"manual"` and check for 3xx statuses yourself. That preserves the no-auto-follow intent on every runtime.

## The exact error
```text
TypeError: Invalid redirect value, must be one of "follow" or "manual" ("error" won't be implemented since it does not make sense at the edge; use "manual" and check the response status code).
```

## Steps
1. Find who passes the bad value. Search your code and your dependencies for `redirect: "error"` or `redirect: 'error'`. It is often a library, not your code: `@slack/web-api`, connect-web based clients, `@better-auth/sso` v1.6.16+, and hand-rolled SSRF-hardened fetch wrappers are all confirmed offenders. Expected outcome: you locate at least one call site, frequently inside node_modules.
2. If it is your code, switch to `"manual"` and handle 3xx explicitly:
```ts
const res = await fetch(url, { redirect: "manual" });
if (res.status >= 300 && res.status < 400) {
  throw new Error("unexpected redirect to " + res.headers.get("location"));
}
```
Expected outcome: the fetch no longer throws at the call site, and a redirect becomes a rejected non-ok response, which is the same anti-SSRF posture `"error"` was meant to give.
3. If it is a library you cannot patch, wrap fetch with an adapter that normalizes only the unsupported value:
```ts
const workerdFetch = (url, init) =>
  globalThis.fetch(url, {
    ...init,
    redirect: init && init.redirect === "error" ? "manual" : init && init.redirect,
  });
```
Pass it as the `fetch` option the SDK exposes (for example `new WebClient(process.env.SLACK_BOT_TOKEN, { fetch: workerdFetch })`). Expected outcome: the SDK keeps working, and a redirect still surfaces as a non-200 response its existing error handling already rejects.
4. Verify under workerd, not just Node. Node's undici accepts `redirect: "error"`, so unit tests and CI pass while production Workers throw. Run the affected path with miniflare or `@cloudflare/vitest-pool-workers`. Expected outcome: the exact TypeError reproduces in the test if the fix is incomplete, and disappears once it is complete.
5. Confirm zero-request behavior is gone. The hallmark of this bug is that the fetch throws before dispatch, so your logs show the error with no corresponding outbound request. After the fix, you should see the request leave and a real status come back. Expected outcome: provider request count goes from 0 to 1 on the previously failing path.

## When to use
Use this when a Cloudflare Worker throws `Invalid redirect value` on a `fetch()` call, when an SDK works on Node but fails on Workers with a TypeError before any network I/O, or when you are hardening server-side fetch against open redirects and want the portable equivalent of `redirect: "error"`.

## When not to use
Not for 4xx or 5xx responses returned by the server (the request went out fine), not for CORS failures, not for redirect loops (those are a `"follow"` problem), and not for `Response.redirect()` throwing on a bad URL, which is a different error about the Location value, not the redirect mode.

## Tool and version compatibility
Cloudflare Workers / workerd, all versions: `redirect: "error"` was never implemented and never will be, per the runtime's own message. Node.js 18+ (undici): accepts all three modes, which is why this bug hides from Node-based tests. Applies to any library that sets the mode, regardless of version.

## Variant phrasings
- `Invalid redirect value, must be one of "follow" or "manual"` (short form, same error)
- `TypeError: Invalid redirect value` (what logs show when the message is truncated)
- `redirect: "error" is unsupported on Cloudflare Workers` (how issues usually title it)

## Root cause, after the fix
The Fetch spec defines three redirect modes, but workerd deliberately implements only two: at the edge, automatically erroring on a redirect adds no value over returning the 3xx and letting the caller decide, so the runtime rejects the mode at the call site with a synchronous TypeError. Libraries written against Node assume all three modes exist. The mismatch only surfaces in production because Node accepts the value, so the failure looks like a network or provider outage (zero requests sent) when it is really a bad option object.

## Edge cases
- The throw happens synchronously inside `fetch()`, before dispatch. Retry loops (the Slack SDK retries transport failures five times) will burn all retries on the same TypeError; fixing the mode is the only fix, not more retries.
- With `"manual"`, a cross-origin redirect returns the 3xx response to you; your explicit status check is what enforces the no-follow policy, so do not skip step 2.
- Some SDKs capture `globalThis.fetch` and call it with the wrong receiver on Workers (`Illegal invocation`); if you see that alongside this error, bind the receiver in the same adapter.
- `Response.redirect(url, status)` throwing is a different failure (invalid Location URL). If your stack shows both, fix the redirect mode first, then validate the URL being redirected to.