Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Schema.isBase64 / isBase64Url throw RangeError on multi-megabyte strings

Open
#9,592 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@magoz is already working on this.

Since Oct 20, 2026.

  • #9593 by @magoz — open

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
Domain
backend, testing

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, cause Cause([Die(RangeError: Maximum call stack size exceeded)]). Schema.is and decodeUnknownResult throw 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Effect-TS/effect

All issues in Effect-TS/effect

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.