validate-inputs-first
Validate Inputs First
Instructions
Before investigating internal logic, always verify that the function receives the correct inputs. A large percentage of bugs are caused by unexpected input data—not broken logic.
Step 1: Catalog Expected Inputs
For the function under investigation, document what each input should be:
EXPECTED INPUT CONTRACT
━━━━━━━━━━━━━━━━━━━━━━
Function: createUser(userData, options)
| Parameter | Type | Required | Shape / Constraints |
|------------|--------|----------|--------------------------------|
| userData | Object | Yes | { name: string, email: string, |
| | | | age: number (>= 0) } |
| options | Object | No | { sendEmail: boolean, |
| | | | role: "admin"|"user" } |
Determine the expected contract from:
- Type annotations / TypeScript interfaces / JSDoc
- Function documentation or comments
- Validation logic within the function
- How callers invoke the function (look at actual call sites)
- Test cases that exercise the function
Step 2: Inspect Actual Inputs
Determine what is actually being passed in:
- Trace upstream: Follow the data from its origin to the function call.
- Check transformations: Identify any mapping, filtering, or formatting applied before the call.
- Look for mutations: Has the data been modified by another function between creation and use?
Document actual vs. expected:
INPUT COMPARISON
━━━━━━━━━━━━━━━━
Parameter: userData
Expected: Actual:
{ {
name: "Alice", name: "Alice",
email: "a@b.com", email: null, ← MISMATCH
age: 30 age: "30" ← WRONG TYPE
} }
Step 3: Identify Mismatches
For each input, check:
- Presence: Is the parameter provided at all? (not
undefined) - Type: Is it the correct data type? (
stringvsnumbervsobject) - Shape: Does the object/array have the expected structure and keys?
- Values: Are the values within valid ranges? (non-empty, positive, valid enum)
- Encoding: Is the data in the expected format? (UTF-8, URL-encoded, base64)
- Staleness: Is the data current, or could it be stale/cached?
Common mismatch patterns:
| Pattern | Example | Usual Cause |
|---|---|---|
undefined parameter |
fn(a, undefined, c) |
Destructuring error, missing prop |
| String instead of number | age: "30" |
Form input, query params, JSON parsing |
| Null instead of object | user: null |
Failed API call, missing DB record |
| Array instead of single item | items: [{...}] vs item: {...} |
API returns list, code expects one |
| Extra wrapping | {data: {data: {...}}} |
Double-wrapped API response |
| Stale data | Correct shape, wrong values | Caching, race condition, stale closure |
Step 4: Trace the Root Cause Upstream
Once a mismatch is found, trace it backward:
- Where does the bad value originate? (API response, user input, database, computation)
- Where does the corruption happen? (transformation, middleware, serialization)
- Why wasn't it caught? (missing validation, no type checking, no tests)
UPSTREAM TRACE
━━━━━━━━━━━━━━
Bad value: userData.email = null
← createUser(userData) [UserService.js:12]
← handleSubmit(formData) [SignupForm.jsx:45]
← formData = getFormValues() [SignupForm.jsx:38]
← email input has name="e-mail" [SignupForm.jsx:15] ← ROOT CAUSE
Mismatch: Form field named "e-mail", code reads "email"
Step 5: Recommend Defensive Measures
After identifying the input issue, suggest:
- Immediate fix: Correct the data at its source
- Validation guard: Add input validation at the function boundary
- Type safety: Add TypeScript types, PropTypes, or schema validation (e.g., Zod, Joi)
- Fail-fast: Throw descriptive errors for invalid inputs instead of silently proceeding
// Example: Adding input validation
function createUser(userData, options = {}) {
// Validate inputs first
if (!userData || typeof userData !== 'object') {
throw new Error('createUser: userData must be an object');
}
if (!userData.name || typeof userData.name !== 'string') {
throw new Error('createUser: userData.name is required and must be a string');
}
if (!userData.email || typeof userData.email !== 'string') {
throw new Error('createUser: userData.email is required and must be a string');
}
// ... proceed with valid inputs
}
Examples
Example 1: API Response Shape Change
User says: "My user list page crashes after the API update."
Expected input: { users: [{id, name, email}] }
Actual input: { data: { users: [{id, name, email}] } }
Root cause: API v2 wraps response in a data envelope. Code reads response.users but should read response.data.users.
Example 2: Type Coercion Bug
User says: "The discount calculation is wrong."
Expected input: discount: 0.15 (number)
Actual input: discount: "15" (string from URL query param)
Root cause: price * discount computes 100 * "15" = 1500 instead of 100 * 0.15 = 15. Query params are always strings.
Troubleshooting
Error: Cannot determine expected input shape
Cause: No types, no docs, no validation—the function accepts anything. Solution: Examine the function body to see which properties/methods it accesses on each parameter. Build the implied contract from usage. Flag the missing contract as a code quality issue.
Error: Input looks correct but function still fails
Cause: The bug is in internal logic, not inputs.
Solution: Confirm inputs are genuinely correct (log them at function entry). If inputs are validated and correct, switch to the trace-execution skill to analyze internal logic.
Error: Input varies across different callers
Cause: Multiple callers pass different shapes. Solution: Check each call site. Identify which caller passes the malformed data. Consider normalizing inputs at the function boundary to accept multiple formats gracefully.
More from blunotech-dev/agents
anti-purple-ui
Enforce a strict monochrome UI with a single high-contrast accent color, removing generic tech gradients and “AI-style” palettes. Use when the user wants minimal, anti-AI, or non-generic aesthetics, or says the UI looks too techy or generic.
9harmonize-whitespace
Align all spacing (padding, margins, gaps) to a consistent 4pt/8pt grid. Use when spacing feels off, inconsistent, cramped, or unbalanced, or when the user asks for a spacing scale or alignment fix.
9typographic-hierarchy
Improve typography by adjusting font sizes, weights, spacing, and contrast to create clear visual hierarchy and readability. Use when text feels flat, unstructured, or when the user asks to refine headings, type scale, or overall readability.
6micro-interaction-adder
Add polished CSS micro-interactions like hover effects, transitions, and feedback states to improve UI feel. Use when the user asks for animations, better UX, or when the interface feels static, plain, or unresponsive.
4consistent-border-radius
Normalizes rounded corners across a file so buttons, inputs, cards, modals, badges, and all UI elements share the exact same curvature. Use this skill whenever the user mentions inconsistent border radii, wants to unify rounded corners, asks to make UI elements look more cohesive, or says things like "make the corners match", "fix the rounding", "unify border radius", "standardize my rounded corners", or "buttons and cards don't match". Also trigger when the user pastes a CSS/HTML/JSX/TSX file and asks for a design consistency pass, border radius is one of the first things to normalize.
4component-split
Analyze a component and determine when and how to split it based on size, responsibility, and reuse signals, producing a refactored structure with clear boundaries. Use when users share large, mixed-concern, or hard-to-test components, or ask about splitting, refactoring, or improving component architecture.
3