Hmbown/CodeWhale · error

invalid draft id

Error message

invalid draft id

What it means

draftKey builds a KV key of the form `draft:<type>:<id>` but first validates the id against DRAFT_ID_PATTERN (/^[A-Za-z0-9._-]{1,128}$/). An id containing colons, slashes, whitespace, unicode, or longer than 128 chars throws "invalid draft id". This prevents malformed or injection-prone ids from entering the KV namespace and keeps parseDraftKey round-tripping.

Solutions

  1. Sanitize or slugify the id to [A-Za-z0-9._-] before calling draftKey.
  2. If the caller holds a full key, use parseDraftKey to extract the id instead of passing the key string as an id.
  3. Trim and cap input length to 128 characters at the API boundary.
  4. Return a 400 with a clear field error when user-supplied ids fail the pattern instead of letting it throw.

Example fix

// before
draftKey(type, rawUserId);

// after
const id = rawUserId.trim().replace(/[^A-Za-z0-9._-]/g, '_').slice(0, 128);
draftKey(type, id);
Defensive patterns

Strategy: validation

Validate before calling

const DRAFT_ID_OK = /^[A-Za-z0-9._-]{1,128}$/;
if (!DRAFT_ID_OK.test(id)) return badRequest('draft id must match [A-Za-z0-9._-]{1,128}');

Type guard

const isValidDraftId = (id) => typeof id === 'string' && /^[A-Za-z0-9._-]{1,128}$/.test(id);

Prevention

When it happens

Trigger: Calling draftKey(type, id) with an id containing ':' or '/' (e.g. a URL path or a UUID with braces), an empty string, whitespace, or a string longer than 128 characters.

Common situations: Passing a full key like 'draft:plan:abc' back in as the id; ids derived from user input (names, emails) with illegal characters; untrimmed input carrying newlines; accepting ids from untrusted POST bodies.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/06fe1d94a066e94c. Report an issue: GitHub.

Appendix: source

Thrown at web/lib/community-agent.ts:65

export interface UsageLog {
  date: string;
  calls: number;
  inputTokens: number;
  outputTokens: number;
}

export interface DeepSeekEnv {
  baseUrl?: string;
  model?: string;
}

const AGENT_DRAFT_TYPE_SET = new Set<string>(AGENT_DRAFT_TYPES);
const DRAFT_ID_PATTERN = /^[A-Za-z0-9._-]{1,128}$/;

export function draftKey(type: AgentDraftType, id: string): string {
  if (!DRAFT_ID_PATTERN.test(id)) {
    throw new Error("invalid draft id");
  }
  return `draft:${type}:${id}`;
}

export function parseDraftKey(key: string): { type: AgentDraftType; id: string } | null {
  const match = /^draft:([^:]+):([^:]+)$/.exec(key);
  if (!match || !AGENT_DRAFT_TYPE_SET.has(match[1]) || !DRAFT_ID_PATTERN.test(match[2])) {
    return null;
  }
  return { type: match[1] as AgentDraftType, id: match[2] };
}

export function isAgentDraft(value: unknown): value is AgentDraft {
  if (!value || typeof value !== "object") return false;
  const draft = value as Record<string, unknown>;
  return (
    typeof draft.id === "string" &&
    DRAFT_ID_PATTERN.test(draft.id) &&

View on GitHub (pinned to 433685b202)