Schema.isBase64 / isBase64Url throw RangeError on multi-megabyte strings
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 20/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Stale
- Tech stack
- typescript
Research direction
Start with the Base64 and Base64Url checks in the Schema string checks and their existing tests. The issue shows the repeated-group regex throws on large valid inputs while flat character checks and the encoding decoders do not; compare those approaches and run the relevant Schema tests. Done means both checks handle multi-megabyte valid input without throwing and reject invalid input as a schema issue.
Written by the indexing model from the issue text.
Description
What version of Effect is running?
4.0.5 (also current main, bbedfc71c0)
What steps can reproduce the bug?
import { Schema } from "effect"
const input = "A".repeat(4_000_000) // valid Base64 / Base64Url, ~3 MB decoded
Schema.decodeUnknownSync(Schema.String.check(Schema.isBase64()))(input)
Schema.decodeUnknownSync(Schema.String.check(Schema.isBase64Url()))(input)
What is the expected behavior?
Both decode successfully (or fail with a schema issue for invalid input).
What do you see instead?
- 4.0.5:
RangeError: Maximum call stack size exceeded main:Error: Sync adapter can only throw schema errors, causeCause([Die(RangeError: Maximum call stack size exceeded)]).Schema.isanddecodeUnknownResultthrow too.
Additional information
The bare regex throws as well, so the problem is the pattern, not Schema:
/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/.test("A".repeat(4_000_000))
// RangeError: Maximum call stack size exceeded
V8's regexp engine keeps backtracking state for each iteration of the repeated (...{4})* group. On Node v24.21.0 (V8 13.6), both patterns accept 3,728,260 chars and throw from 3,728,264 chars (932,066 groups, ~2.67 MiB decoded). Base64 strings produced by Buffer#toString("base64") fail at the same length. The limit stays the same with --stack-size=400 and --stack-size=4000. Non-capturing (?:...) groups also throw at 8M chars. A flat ^[0-9a-zA-Z+/]*$ does not, and neither do Base64.decode / Base64Url.decode from effect/encoding (~20 ms at 8M chars).
In practice, Base64 payloads such as file attachments above ~2.7 MB cannot be validated. I checked the other regex-backed string checks (isTrimmed, isUUID, isGUID, isULID, isStringFinite, isStringBigInt, isStringSymbol, isUppercased, isCapitalized, isStartingWith) on 8M-char inputs, and none of them throw.
- Dominant language
- TypeScript
- Stars
- 16.7k
- Forks
- 808
- Avg merge
- 10h 12m
- Merged PRs (30d)
- 813
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Effect-TS/effect
-
BrowserWorkerRunner: port finalizer throws when the worker global has no close() (Bun)Possibly taken @santiago-ramos-02 claimed this 20 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Effect-TS/effect#8635 · 3 comments ·
Maintainers usually reply within 1 day
-
Support {self: this} for fnUntracedMay be free again @ArjunCodess claimed this 32 days ago, and no pull request is open. Openenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Effect-TS/effect#8101 · 1 comment ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 32/100
Effect-TS/effect#9610 · 2 comments ·
Maintainers usually reply within 1 day
-
Schema.isStringFinite (and Number string matching) takes quadratic time on long digit runsPossibly taken @magoz claimed this 1 day ago. Open
Difficulty 3/5 1-2 days Newbie friendliness 66/100
Maintainers usually reply within 1 day
-
PersistedQueue SQL store: a stale handler's retry releases the newer claim its own worker made, so the element is delivered again while in flightPossibly taken @effect-bot claimed this 1 day ago. Open
Effect-TS/effect#9591 · 1 assignee ·
Maintainers usually reply within 1 day
All issues in Effect-TS/effect
Similar issues
-
check:passed streams:edit
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
area:mcp bug has repro platform:vscode regression
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
anthropics/claude-code#103970 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day
-
sdk-typescript: unquoted COPY globs in shell form are silently dropped from the image build contextOpenbug javascript
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day