Client-side token counting validates user input before submission
Why it matters
Server-side-only validation for empty or oversized inputs forces every request through a full network round-trip before a basic error surfaces, wasting LLM API spend on requests that will be rejected and burning user patience on latency that could be zero. A user pasting a 200KB document into a chat box discovers the limit after the spinner, not before. Client-side input validation short-circuits these failures at the keyboard, cutting wasted provider tokens and improving perceived performance for the user-experience taxon this pattern tracks.
Severity rationale
Low because the failure mode is latency and wasted tokens, not data loss or security compromise.
Remediation
Add a character-count check and disabled submit button to the chat input component at src/components/chat-input.tsx. Track input length in local state, compute isOverLimit against a fixed ceiling, and block the form onSubmit when the input is empty or exceeds it. Show a live counter past a warning threshold so users self-correct before sending.
const MAX_CHARS = 20000;
const isOverLimit = input.length > MAX_CHARS;
<button type="submit" disabled={!input.trim() || isOverLimit}>Send</button>
Detection
-
ID:
client-side-input-validation -
Severity:
low -
What to look for: In the chat input component or form, look for client-side validation of the input length before the form submits. This could be: a character or word count check, a disabled submit button when input is empty or exceeds a threshold, a visual token counter displayed to the user, or a client-side import of a tokenizer library. Also check for server-side-only validation where the request must round-trip before basic input errors are caught. Count all instances found and enumerate each.
-
Pass criteria: The UI prevents or warns on submission when user input is empty or clearly exceeds a reasonable limit (e.g., character count > 20,000). Ideally, a token counter is shown so users can manage their input length proactively. At least 1 implementation must be confirmed.
-
Fail criteria: Validation is server-side only — the frontend submits any input length without client-side checks, requiring a round-trip before basic errors (empty input, excessively long input) are caught.
-
Skip (N/A) when: The application has no user input form — it operates entirely on server-side or programmatically generated prompts. Signal: No
<input>,<textarea>, oruseChathook usage in any frontend component. -
Detail on fail:
"No client-side input validation — empty or oversized inputs require server round-trip to catch" -
Remediation: Server-side validation for basic input errors (empty, too long) adds unnecessary latency and wastes server resources. Client-side checks catch these immediately.
// src/components/chat-input.tsx const MAX_CHARS = 20000; const WARN_CHARS = 15000; export function ChatInput({ onSubmit }: { onSubmit: (input: string) => void }) { const [input, setInput] = useState(""); const isOverLimit = input.length > MAX_CHARS; const isNearLimit = input.length > WARN_CHARS; return ( <form onSubmit={e => { e.preventDefault(); if (!isOverLimit && input.trim()) onSubmit(input); }}> <textarea value={input} onChange={e => setInput(e.target.value)} maxLength={MAX_CHARS + 100} // soft enforcement /> {isNearLimit && ( <p style={{ color: isOverLimit ? "red" : "orange" }}> {input.length.toLocaleString()} / {MAX_CHARS.toLocaleString()} characters {isOverLimit && " — input too long"} </p> )} <button type="submit" disabled={input.trim().length === 0 || isOverLimit}> Send </button> </form> ); }Verify by attempting to submit an empty message (button should be disabled) and pasting a very long text (counter should appear and submission should be blocked).
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ai-token-optimization·automated