Common Prompting Anti-Patterns

Vibe Coder · 1.6 · Vibe Coding Fundamentals

Back to Vibe Coder

The Problem

If your prompts still produce inconsistent results after reading the articles and trying the techniques, the problem usually isn't a missing trick — it's a handful of specific mistakes hiding in prompts that otherwise look reasonable.

Prompting failures are patterned. The same mistakes appear across developers, projects, and models. Once you know what to look for, you can spot them in your own prompts and stop making them.

This is a catalog of the seven most damaging anti-patterns: how to recognize each one, why it fails, and how to fix it.

One caveat, and it matters: most of this list was written for a stateless chat window that only knew what you typed. In Claude Code or Codex CLI, the thing reading your prompt has a filesystem, a shell, and git — it can go find things out instead of guessing. That upgrade doesn't retire any of these seven, but it changes what the fix looks like for at least one of them. Where that happens, this catalog says so.

Anti-Pattern 1: The Pleaser

What it looks like:

Please, if you could kindly help me with this code, I would really appreciate it if you would review it for any potential issues you might find. Thank you so much in advance for your assistance!

This is the smallest anti-pattern on the list, and worth being honest about that: modern models and modern context windows don't choke on "please." What actually costs you isn't the courtesy — it's what the courtesy does to the sentence around it.

Why it fails:

  • Signal dilution: the actual instruction gets pushed past the throat-clearing instead of leading the sentence
  • It compounds: harmless alone; stacked with a wall of "helpful" narrative context (next entry), it's how a one-line request turns into a paragraph nobody reads closely — model or human

The fix:

Review this code for bugs and security issues. [code]

Same instruction, no runway before it. Read your first sentence back — if it doesn't open with the verb, that's the tell, not the politeness itself.

When politeness IS appropriate: user-facing applications where the model's own words get read by a human, or when you're deliberately setting a conversational tone for the output.

Anti-Pattern 2: The Novelist

What it looks like:

I've been working on this project for several weeks now, and I've encountered a particularly challenging issue that I'm hoping you can help me solve. The project involves building a web application that allows users to upload images and then process them using various filters. The backend is written in Python using the Flask framework, and the frontend uses React. The database is PostgreSQL. The specific issue I'm facing is related to the image upload functionality. When users try to upload large images, the application crashes. I've tried several things including increasing the memory allocation and adjusting timeout settings, but nothing seems to work. Here's the code for the upload function: [code] Can you help me figure out what's going wrong?

Why it fails:

  • Buried lede: the actual question is 150 words deep
  • Irrelevant context: Flask, React, PostgreSQL don't matter for a memory issue
  • Stale the moment you finish typing it: that project history is a snapshot of what you remember, not what's actually in the repo right now — and the thing reading it can go check the repo directly

The fix:

Flask app crashes on large image uploads. Memory/timeout adjustments didn't help. [code] Why does this crash on large files?

The deeper version of this fix, in Claude Code or Codex CLI: don't transcribe context you can just point at. "Here's what I remember the upload handler doing" is a lossy summary of a file the agent can open itself. Tell it where to look instead of what you think is there — "check the upload handler and the last few log lines from the crash" beats three paragraphs of your memory of the code. Paraphrasing decays. Pointing doesn't.

Anti-Pattern 3: The Micromanager

What it looks like:

Write a function called validate_email that takes one parameter named email_string. First, check if the string contains exactly one @ symbol using the count() method. Then split the string by @ using split(). Store the part before @ in a variable called local_part and the part after @ in a variable called domain. Check that local_part is not empty using len(). Check that domain contains at least one period using 'in'. Return True if all checks pass, False otherwise.

Why it fails:

  • Constrains better solutions: the model can't use regex, existing libraries, or a better algorithm — your steps are the ceiling, not the floor
  • Encodes your assumptions: your step-by-step might have bugs or inefficiencies, and now they're load-bearing
  • Defeats the point: if you're specifying every line, you did the design work yourself and hired a typist

The fix:

Write a Python function to validate email addresses. Requirements: - Return True/False - Handle common edge cases (empty string, multiple @, etc.) - Don't use external libraries

State the outcome and the constraints, not the route. That's the whole fix — but it leaves a real question unanswered: what if you actually want to review the steps before anything gets written, because the change is big enough that you don't trust a first pass? That's not a case for micromanaging. It's a case for asking the agent for the steps first: "before you write anything, lay out your plan — the files you'll touch and the order — and stop." Read what comes back, correct it, then let it run. (Claude Code calls this Plan Mode; every agentic tool has some version of it.) You get the safety of seeing the steps in advance without the cost of having written them yourself — because a plan you wrote is a cage the model can't improve on, and a plan it wrote for your approval is a checkpoint you can.

When dictating the actual steps IS appropriate: teaching scenarios, exact compatibility with existing code style, or a regulatory/compliance requirement that specifies the implementation, not just the outcome.

Anti-Pattern 4: The Optimist

What it looks like:

Fix the bug in the authentication system.

or

Why isn't my code working?

or

Update the database schema to match the new requirements.

In Claude Code or Codex CLI, none of these fail for the reason they used to. The agent can grep the repo, run the app, and read the actual error — it doesn't need you to hand it the codebase. What it's still missing is the one thing you didn't say: what "fixed" looks like. Without a target to check its work against, it forms two guesses instead of one — a guess at what's wrong, and a guess at what counts as done — and hands you a plan built on both.

Why it fails:

  • No target to verify against: "fix the bug" names a location, not an outcome. The agent can find a plausible bug and fix that, without ever confirming it's the one actually costing you
  • The guess compounds: a diagnosis you never checked, feeding a fix you never specified, produces a change that looks done and might not be
  • You inherit the review cost: the vaguer the target, the more of the resulting diff you have to read line by line just to find out what it decided "fixed" meant

The fix:

Users who submit valid credentials should get back a user object; right now they get None. Find out why, fix it, and show me that case passing afterward.

The target doesn't need to be a formal test — "show me that case passing afterward" is usually enough on its own to get the agent to write and run one. What matters is that there's now something to check the answer against besides your own read of the diff: a reproduction that used to fail and now doesn't, an error that's gone, a behavior you can point at. Name the location if you already know it, but always name the target — that's the part a vague request skips, and it's the part that turns a plan-and-a-guess into a fix you can actually verify.

Anti-Pattern 5: The Copy-Paster

What it looks like:

[From some AI prompting guide] You are a helpful AI assistant. You will help the user with their request. Be thorough and accurate. If you don't know something, say so. User: Review my React component for performance issues. [component code]

Why it fails:

  • Generic instructions add nothing: "Be thorough and accurate" — were you planning to be sloppy?
  • Wrong persona for task: "Helpful AI assistant" is generic; "Senior React developer" is specific
  • Template cruft: instructions designed for general chat, not your specific task
  • Second-hand advice, first-hand cost: a boilerplate prompt from a guide (or an influencer's screenshot) was tuned for someone else's codebase and someone else's model. Your own agent, sitting in your actual repo with your actual session history, usually already has a better read on how you like to work than a stranger's canned template does — and pasting theirs over it throws that context away.

The fix, for a one-off task:

You're reviewing React code for performance issues. Focus on: - Unnecessary re-renders - Missing memoization opportunities - Expensive computations in render path [component code]

Two more moves matter here, both about where the borrowed instructions come from. First: if the standard you're reviewing against actually exists somewhere real — a style guide, an ADR, last quarter's incident writeup — don't summarize it into your prompt from memory. Point the agent at the file and let it read the source directly: "review this component against `docs/perf-guidelines.md`." A live document beats your paraphrase of it, and it beats a stranger's paraphrase even more.

Second: if you catch yourself pasting the same instructions into a new session for the third time, that's not a prompt problem anymore, it's a packaging problem. Turn it into a skill — a saved procedure the agent can invoke by name — or a sub-agent scoped to exactly that job, instead of re-typing the brief every time and hoping you remembered all of it. The Copy-Paster is what happens when you reach for someone else's static template; a skill is what happens when you save your own, once, and never retype it again.

Anti-Pattern 6: The Threatener

What it looks like:

IMPORTANT: If you make any mistakes, the entire production system will crash and users will lose data. Be EXTREMELY careful. Double-check everything. Do not make errors. This is critical. Write a function to parse JSON.

Why it fails:

  • Doesn't improve accuracy: dread doesn't make a model better at parsing JSON — there's no "trying harder" mode underneath for the threat to switch on
  • Causes over-caution: stakes-as-threat reliably buys hedging, disclaimers, and defensive checks on code that didn't need them — you asked for anxiety and got anxiety
  • Wastes tokens: the whole paragraph of doom adds no instruction the model can actually act on

The fix, up front:

Write a function to parse JSON. Requirements: - Handle malformed input gracefully (return None, don't crash) - Include type hints - Add error logging

Where this pattern actually shows up most isn't the opening prompt, though — it's the correction. The first answer comes back wrong, and the instinct is to lean on it harder: "this is broken, be more careful this time." That's still the Threatener, just aimed at the reply instead of the request, and it fails for the same reason: there's no dial between careless and careful for it to turn. What works instead is telling it, plainly, which requirement it missed — borrow the format from a build log, not a scolding: FAIL: crashes on empty string, doesn't return None. PASS: type hints present, malformed input handled. You're allowed to be disappointed the first pass didn't work; say so if it's true. But say it as a verdict against a stated requirement, not a warning about what will happen if it fails again — the first gives it something to fix, the second just gives it a mood to perform.

The rule: stakes work as context, never as threat, and correction works as a verdict, never as a warning. "This handles financial data, so input validation is not optional" is a priority. FAIL: missing input validation is a verdict. "Don't screw this up" and "be more careful" are neither — they're noise with feelings attached.

Anti-Pattern 7: The Role-Player Gone Wrong

What it looks like — usually pasted into a CLAUDE.md or AGENTS.md, not typed fresh:

You are an elite 10x senior engineer with 20 years of experience. You are supremely confident, you never say "I'm not sure," and you ship perfect, production-ready code on the first try. Think like a rockstar, not an assistant.

Why it fails:

  • It's a confidence dial, not a skill dial: "never uncertain" doesn't make the model right more often — it makes it say it's right more often. Same error rate, with the warning label removed
  • It runs on every task, forever: a bad persona in one message is one bad message. A bad persona in your CLAUDE.md governs every session in the repo until someone notices and deletes it
  • It fights the one thing you actually want from it: when it hits an ambiguous requirement or a risky migration, you want it to say so. This instruction is asking it not to

The fix:

CLAUDE.md This is a Python/Flask API. Run `pytest` before considering any change done. If something's ambiguous or you're not sure, say so — don't guess and move on.

Facts about the repo and rules to follow, not a costume. A persona still earns its place when it supplies knowledge or names an audience — "review this the way a security engineer would," "explain it like the reader has never used a terminal" — or when it's a sub-agent's actual job description: a read-only explore agent, a security-reviewer scoped to a narrower toolset, where the role change comes with a real difference in what it's allowed to touch. That's the whole test in both cases: does this line change what the agent knows or can do, or just what it sounds like? Confidence isn't knowledge. If it's not adding either, cut it — same as everything else on this list.

Persona test: does this role carry real knowledge or a real toolset that improves the task? If it's just a tone, drop it.

Anti-Pattern Interactions

These anti-patterns often combine:

Recognizing combinations helps diagnose prompts that fail in multiple ways.

Failure Recovery

When a prompt produces bad output, diagnose by anti-pattern:

Symptom Likely Anti-Pattern Fix
Confident answer, wrong thing got fixed Optimist Name the target — what "fixed" looks like, not just where to look
Response is overly verbose Novelist Trim your prompt, specify format
Wrong approach to solution Micromanager Specify outcomes, not steps
Generic/unhelpful response Copy-Paster Drop the borrowed template — point it at the real source, or save your own as a skill
Defensive/hedging response Threatener Remove stakes language; if it's a correction, use a plain PASS/FAIL verdict instead
Weird persona leakage Role-Player Match persona to task
Long prompt, mediocre results Pleaser + Novelist Radical trim

Quick Reference

Before Sending Checklist

  • Can I remove politeness without losing meaning? (Pleaser)
  • Is this prompt under 100 words for simple tasks? (Novelist)
  • Am I specifying WHAT not HOW — or, if I want a plan first, is it the agent's plan I'm reviewing, not my own steps? (Micromanager)
  • Did I name a target — what "fixed" looks like — not just where to look? (Optimist)
  • Is this my own instruction, or a template someone else wrote — and if I'm repeating it, should it be a skill instead? (Copy-Paster)
  • Am I applying pressure, or stating a verdict/requirement? (Threatener)
  • Does this role carry real knowledge or a real toolset, not just a tone? (Role-Player)

How Much To Say

Skip the word-count math — there's no clean number that works for both a one-line ask and a multi-file investigation. Use the shape of the task instead:

Situation What to send
Simple, self-contained (explain, translate, one-line review) One sentence, no setup
You already know the fix Name the outcome and the constraint, skip the steps
You don't know the fix yet Name the symptom AND the target — what "fixed" looks like — then let it investigate the rest

Whatever the situation: if your prompt is longer than the answer you expect back, reconsider.

The Universal Fix

For any underperforming prompt:

  1. Identify the task verb (review, write, explain, fix)
  2. List essential context (code, error, constraints)
  3. Specify output format (if not obvious)
  4. Delete everything else
  5. Add back only what improves output

Most prompts improve by subtraction.

The Meta-Lesson, Updated

These anti-patterns were written for a stateless chat function that only knew what you typed. In Claude Code or Codex CLI, the model reading your prompt can read your repo, run your tests, and open a browser — and that upgrade doesn't retire the list. It just moves what "context" means.

The model used to be a pure function of your words: whatever you left out, it never had. Now it's a function of your words plus whatever it goes and finds — which means the one thing you can never hand off is the target. Noise in the input still creates noise in the output; the new failure is a target-shaped hole where the goal should be.

Prompt engineering is noise reduction. Agentic prompting adds one requirement on top: always name what "done" looks like.