Skip to content

feat(utilities): add validateKvsKey with named illegal-character diagnostics - #666

Draft
DaveHanns wants to merge 1 commit into
masterfrom
fix/f84-kvs-key-illegal-chars
Draft

feat(utilities): add validateKvsKey with named illegal-character diagnostics#666
DaveHanns wants to merge 1 commit into
masterfrom
fix/f84-kvs-key-illegal-chars

Conversation

@DaveHanns

Copy link
Copy Markdown
Contributor

Summary

Add validateKvsKey and assertValidKvsKey in @apify/utilities so callers that reject key-value store record keys can produce an error message that names the actual problem instead of restating the entire allowed charset plus the length limit.

Motivation

The current pattern for validating a KVS record key is to test it against KEY_VALUE_STORE_KEY_REGEX in @apify/consts and, on failure, throw a message like:

The "key" argument "price:yamaha-ysp-5600-<...>" must be at most 256 characters long and only contain the following characters: a-zA-Z0-9!-_.'()

That message conflates two independent checks (charset AND length) and forces the caller of the API to diff their key against the allowed set by hand. In the example above, the length is fine and the only problem is a single colon — but the user has to figure that out themselves. This is especially painful when the key contains an invisible character (a stray tab, a trailing newline, a non-breaking space).

What this change adds

validateKvsKey(key) returns a discriminated union:

  • On success: { valid: true }.
  • On failure: { valid: false, illegalCharacters, tooLong, empty, message } where
    • illegalCharacters is the deduplicated list of characters not in a-zA-Z0-9!-_.'(), in order of first appearance;
    • tooLong is true when key.length > 256;
    • empty is true when the key is the empty string;
    • message is a ready-to-use human-readable string, e.g.
      Key-value store record key is invalid (illegal character(s): ":" (colon)). Allowed characters are a-zA-Z0-9 and !-_.'(), max length 256.
      

Length and charset are reported independently: a key that both contains a bad character AND exceeds 256 chars now gets both diagnostics; a key with only a bad character no longer falsely blames length.

Whitespace and control characters get a friendly name ((space), (tab), (newline), U+0007 …) so the failure is unambiguous even when the offending char is invisible in a terminal.

assertValidKvsKey(key) is a thin throwing wrapper for callers that just want to guard.

Test plan

test/kvs_key_validator.test.ts covers:

  • Valid keys (including it's-fine, INPUT, file.json, a, 0, and a key at exactly 256 chars).
  • Empty key → empty: true, no length/charset noise.
  • Key with a single illegal char (price:yamaha-ysp-5600) → illegalCharacters: [':'], message contains illegal character(s): ":" (colon), message does NOT match /length \d+ >/.
  • Duplicate + multiple illegal chars → deduplicated in first-seen order.
  • Length-only failure → illegalCharacters: [], message contains length 257 > 256, no charset noise.
  • Length + charset failure → both problems reported.
  • Whitespace chars get named ((space), (tab), (newline)).
  • assertValidKvsKey throws TypeError with the composed message.

Ran locally:

$ pnpm vitest run test/kvs_key_validator.test.ts
 Test Files  1 passed (1)
      Tests  10 passed (10)

$ pnpm --filter @apify/utilities run build
DTS Build success

$ pnpm lint
Found 0 warnings and 0 errors.

Follow-ups (not in this PR)

Consumers that currently reject KVS keys by hand-rolling their own error message (notably the storage error in the Apify core API) can be migrated to validateKvsKey in a separate change — this PR only adds the utility and its tests.


Surfaced during an evaluation of Apify surfaces for agent-driven Actor development.

…nostics

Add `validateKvsKey` / `assertValidKvsKey` in `@apify/utilities` so callers
that reject key-value store record keys can produce a message that names
the actual problem instead of restating the entire allowed charset plus
length limit.

When a key like `price:yamaha-ysp-5600` is rejected, the current pattern
for callers of `KEY_VALUE_STORE_KEY_REGEX` in `@apify/consts` is to say
"must be at most 256 characters long and only contain the following
characters: a-zA-Z0-9!-_.'()" — which forces the user to diff their key
against the charset by hand. `validateKvsKey` returns the deduplicated
list of illegal characters (in order of first appearance), a length flag,
and an empty flag, plus a composed `message` like:

    Key-value store record key is invalid (illegal character(s):
    ":" (colon)). Allowed characters are a-zA-Z0-9 and !-_.'(),
    max length 256.

Length and charset problems are reported independently, so keys that
exceed 256 chars AND contain a bad char get both diagnostics; keys with
only a bad char no longer falsely blame length.

Surfaced during an evaluation of Apify surfaces for agent-driven Actor
development.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@DaveHanns
DaveHanns marked this pull request as draft July 5, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants