## TL;DR

KV keys are capped at 512 bytes. Keys built by concatenating URLs, query strings, or user content blow past it. Hash the variable portion (SHA-256 hex is 64 bytes) and keep a short readable prefix, so keys stay tiny and deterministic.

## The query

```text
workerd error: KV key length exceeds 512 bytes
```

## Use this when

- KV put fails naming key length.
- Keys embed full URLs, long slugs, or serialized parameters.
- The failure started when inputs got longer.

## Not for

- 'KV value exceeds 25 MiB' (value limit, separate fix).
- 'binding is not defined' (binding config problem).
- Reads returning null (missing key, separate fix).

## Steps

### Step 1: Measure the offending keys

Log the byte length of the key at write time (bytes, not characters; multibyte unicode counts more).

Expected result: the failing keys measure over 512 bytes. You now know how much must go.

### Step 2: Hash the variable portion

```js
async function kvKey(prefix, raw) {
  const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(raw));
  const bytes = Array.from(new Uint8Array(digest));
  const hex = bytes.map(function(b) { return b.toString(16).padStart(2, "0"); }).join("");
  return prefix + ":" + hex;
}
const key [your value] kvKey("page", request.url);
```

Expected result: keys are a short prefix plus 64 hex characters, always under the limit, deterministic for the same input.

### Step 3: Keep a readable prefix, not the readable key

The prefix (`page:`, `session:`, `redirect:`) keeps keys debuggable in listings. The hash carries uniqueness. Do not keep truncating the raw string instead; truncation collides.

Expected result: keys stay human-scannable in the dashboard while never exceeding the limit.

### Step 4: Migrate existing long keys

If long keys were written before (by a path that did not validate), backfill them to the hashed form or accept that old entries expire.

Expected result: no code path can produce an over-limit key again. Add a length assertion in the key builder.

### Step 5: Verify writes succeed

Expected result: puts succeed and reads with the same builder function hit. Both sides must use the identical builder.

## Why it happens

KV is designed for short lookup keys; the 512-byte cap keeps the index fast. Application code treats the key as a free-form string and stuffs entire URLs or JSON blobs into it. It works until the first long input, usually from real user data.

## Edge cases

- Byte length, not character length. Emoji and CJK characters are 3-4 bytes each in UTF-8.
- Listing by prefix still works with hashed keys as long as the prefix is stable.
- If you need the original value back, store it inside the KV value or in a lookup table; the hash is one-way.
- The 512-byte limit applies to the full key including prefix. Budget the prefix inside the limit.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_NGi8bY_vrVyz1fkOuoyMww
