Skip to content

fix(type): keep uppercase UUIDs valid in string.uuid JSON Schema - #1670

Merged
ssalbdivad merged 1 commit into
arktypeio:mainfrom
breken-ai:fix/uuid-json-schema-uppercase
Oct 1, 2026
Merged

ssalbdivad merged 1 commit into
arktypeio:mainfrom
breken-ai:fix/uuid-json-schema-uppercase

Conversation

@breken-ai

Copy link
Copy Markdown
Contributor

The string.uuid regexes (#versioned and v1 to v8) use the i flag so that uppercase hex digits are allowed. toJsonSchema() exports only the regex source as pattern, because JSON Schema has no way to carry flags. As a result the exported schema is stricter than the runtime check and rejects valid uppercase UUIDs:

const Uuid = type("string.uuid.v4")
const upper = "F70B8242-DD57-4E6B-B0B7-649D997140A0"

Uuid(upper) // ok
Uuid.toJsonSchema()
// { type: "string", pattern: "^[\\da-f]{8}-[\\da-f]{4}-4[\\da-f]{3}-[89ab][\\da-f]{3}-[\\da-f]{12}$" }
// ajv / any JSON Schema validator: rejects `upper`

string.uuid has the same problem. Its format: "uuid" branch still carries the lowercase-only pattern, so even validators that treat format: "uuid" as case-insensitive (ajv-formats does) reject the value. Uppercase UUIDs are common in practice: SQL Server uniqueidentifier values, Swift UUID().uuidString and Windows GUIDs are all uppercase. So an API that validates with arktype on the server and publishes the generated JSON Schema/OpenAPI to clients ends up with clients that reject payloads the server accepts.

Fix: list both cases in the character classes ([\dA-Fa-f], [89ABab]) and drop the i flag. string.hex already does it this way. Runtime behaviour is unchanged (the same strings match), and the exported pattern now agrees with it.

A more general follow-up could have PatternNode.reduceJsonSchema handle flagged regexes (for example through a fallback code), since user regexes like /^abc$/i lose their flag the same way. I kept this PR to the built-in keyword so it stays a single, behaviour-preserving fix.

Test: added a case to ark/type/__tests__/keywords/uuid.test.ts. It checks that string.uuid and string.uuid.v4 accept an uppercase UUID at runtime, and that the exported pattern, compiled without flags as JSON Schema validators do, matches it too.

  • Before the fix: 1 failing (false !== true)
  • After the fix: 4/4 passing in uuid.test.ts
  • I also checked the exported schemas with ajv 8 (draft 2020-12): uppercase v4 and root UUIDs were rejected before the fix and are accepted after it.

Checklist:

  • Code is up-to-date with the main branch (based on 42c17df)
  • You've successfully run pnpm prChecks locally: I ran part of it. pnpm test passes (1752 passing), tsc is clean, and prettier and eslint --max-warnings=0 pass on the changed files. I did not run the benches, buildRepo or testTsVersions.
  • There are new or updated unit tests validating the change

I used an AI coding assistant to find and fix this, and I checked the change and the before/after test results myself.

The string.uuid regexes relied on the i flag for uppercase hex digits.
toJsonSchema only exports the regex source as `pattern`, so the flag was
dropped and the exported schema rejected uppercase UUIDs that the
runtime check accepts.

List both cases in the character classes instead, as string.hex already
does, so runtime validation is unchanged and the exported pattern
matches the same strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • UUID regexes no longer rely on the i flag — #versioned and v1–v8 in ark/type/keywords/string.ts now spell out [\dA-Fa-f] / [89ABab] explicitly, so the pattern emitted by toJsonSchema() matches the runtime check instead of silently dropping the flag.
  • Regression test added — uuid.test.ts asserts uppercase input is accepted at runtime for string.uuid and string.uuid.v4, and that the exported pattern compiles and matches it.

I verified the change is behavior-preserving (the explicit classes are equivalent to the previous [\da-f]/[89ab] with i), confirmed via a local probe that the pre-fix schema emitted the lowercase-only pattern while the runtime accepted uppercase, and confirmed the new test fails against the base revision and passes here. Full suite: 1752 passing.

Scoping the fix to the built-in keyword and leaving flagged user regexes (/^abc$/i) to a separate follow-up is the right call — that broader PatternNode.reduceJsonSchema gap is pre-existing and not a regression this PR introduces.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@ssalbdivad ssalbdivad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on the flag getting dropped, thanks!

@ssalbdivad
ssalbdivad merged commit 0f88b51 into arktypeio:main Oct 1, 2026
7 checks passed
@ssalbdivad ssalbdivad mentioned this pull request Oct 1, 2026
4 tasks done
ssalbdivad added a commit that referenced this pull request Oct 1, 2026
Bumps all publishable packages and documents the changes merged since 2.2.6:

- fix `this[]` in self-referential object types (#1618, fixes #1406,
  @yharaskrik)
- parse string.date.epoch.parse input as milliseconds (#1669, @breken-ai)
- keep uppercase UUIDs valid in string.uuid JSON Schema (#1670,
  @breken-ai)
- render nested bigints correctly in error messages (#1626, fixes #1477,
  @chatman-media)
- release unused parse ids from the global registry (#1673, fixes #1584
  for equivalent types, @isaacwasserman)
- fix crashes on Hermes and Turbopack (#1674, fixes #1645 and #1643)

#1590 only adds tests, so it has no changelog entry.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done (merged or closed)

Development

Successfully merging this pull request may close these issues.

2 participants