Does Replit Agent Catch Missing Error Handling? (And What to Run If It Doesn't)
By Nark Team
No, Replit Agent 4 does not catch missing error handling around the npm packages it imports. Its only quality layer is in-browser self-testing of happy paths, which never triggers the failure modes that Stripe webhooks, Prisma queries, and openai calls hit in production. To catch those gaps before deploy, run npx nark --tsconfig ./tsconfig.json in your Repl shell.
Quick Answer: Replit Agent 4 self-tests happy paths in a browser; it does not statically check that your code handles npm-package errors. Run
npx nark --tsconfig ./tsconfig.jsonin your Repl shell to catch missing try/catches around Stripe, Prisma, openai, axios, and 160+ other packages.
What does Replit Agent 4 actually check?
Replit Agent 4 has exactly one published quality claim, taken verbatim from the product page: "Agent tests its own work so you don't have to." The mechanism is a proprietary in-browser testing system. Agent generates your app, opens it in a browser, exercises the visible flow, generates a report, and fixes the issues it observes.
That is useful for one specific class of problem: visible UI breakage on the happy path. Did the page render? Did the form submit? Did the route return a 200? Browser self-testing catches those.
What it does not check, because no browser flow ever triggers it:
- A try/catch missing around
stripe.paymentIntents.create()when the card is declined - A Prisma query that throws
PrismaClientKnownRequestErrorwith codeP2002on a unique-constraint collision - An
openai.chat.completions.create()call that returns HTTP 429 because the API key hit a rate limit - A
pgquery that throws on a closed connection mid-transaction - An
axios.get()call against a flaky third-party API that returns 500 once an hour
These are package-level error contracts. Each library documents what it throws and when, and the right pattern is to wrap the call in a try/catch and branch on the error type. AI code generators routinely skip these wrappers because their training distribution is full of "minimal example" snippets that omit error handling. Replit Agent's browser self-test never sees a card decline, a duplicate insert, or a 429, so it never asks whether your code would survive one.
There is no static-analysis layer, no dependency-aware error checker, and no lint rule on the Replit Agent product page. The gap is real and Replit has not announced a roadmap to close it.
How good is Replit Agent code quality in 2026?
Honest answer: strong on the visible layer, weak on the package layer.
Replit Agent 4 produces UI that renders, routes that return 200, forms that submit, and database tables that get created. Its browser self-testing system catches the visible regressions a human would also catch by clicking around for two minutes. For prototypes, internal tools, and first-launch demos, that quality bar is genuinely useful.
Code quality breaks down on the layer browser self-testing cannot see: error handling around the npm packages your code imports. Agent generates the happy path, the browser-test exercises the happy path, and both pass. The first time a card is declined, a unique constraint is hit, or an API rate limit fires in production, the unhandled error propagates and the route crashes. That is not a quality claim Replit makes and it is not a layer Replit has shipped yet. If you are running a Repl past the demo phase, you are responsible for that layer yourself, and npx nark is the most direct way to check it.
What kinds of errors does Replit Agent miss?
Three concrete examples, drawn from the npm packages Replit Agent generates code for most often. Each shows the wrong-way pattern (what Agent produces) and the right-way pattern (what your code needs to look like before deploy).
Does Replit Agent wrap stripe.paymentIntents.create in a try/catch?
Replit Agent will happily write a checkout route that calls stripe.paymentIntents.create() without wrapping it. In a browser self-test against a Stripe test card that succeeds, the route returns 200 and Agent's check passes. In production, the first declined card crashes the route.
// Wrong way: what Replit Agent typically generates
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function createPaymentIntent(amountCents: number) {
const intent = await stripe.paymentIntents.create({
amount: amountCents,
currency: 'usd',
});
return intent;
}
// Right way: branches on the documented Stripe error classes
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function createPaymentIntent(amountCents: number) {
try {
const intent = await stripe.paymentIntents.create({
amount: amountCents,
currency: 'usd',
});
return intent;
} catch (error) {
if (error instanceof Stripe.errors.StripeCardError) {
// Card was declined. Tell the user, do not retry.
throw new Error(`Card declined: ${error.message}`);
}
if (error instanceof Stripe.errors.StripeAPIError) {
// Transient Stripe outage. Safe to retry with backoff.
throw new Error(`Stripe transient error: ${error.message}`);
}
throw error;
}
}
The right-way version names two of Stripe's documented error classes: StripeCardError (card declined, invalid CVC, expired card) and StripeAPIError (Stripe's own infrastructure had a problem). Each one demands different recovery logic. Without the catch, the route returns a 500 and the user has no idea why their payment did not go through.
Does Replit Agent catch PrismaClientKnownRequestError P2002 on duplicate inserts?
Prisma documents a specific error class for query failures: PrismaClientKnownRequestError. Each instance carries a code property that maps to a documented condition. The most common one is P2002, raised when a unique constraint is violated (e.g. trying to create a user with an email that already exists).
// Wrong way: what Replit Agent typically generates
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export async function createUser(email: string, name: string) {
const user = await prisma.user.create({
data: { email, name },
});
return user;
}
// Right way: branches on Prisma error codes
import { PrismaClient, Prisma } from '@prisma/client';
const prisma = new PrismaClient();
export async function createUser(email: string, name: string) {
try {
const user = await prisma.user.create({
data: { email, name },
});
return user;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === 'P2002') {
// Unique constraint violation. The email is already taken.
throw new Error('Email already registered');
}
}
throw error;
}
}
The wrong-way version crashes the route on a duplicate email, returns a 500, and the user sees "Internal Server Error" instead of "Email already registered." The browser self-test never triggers it because Agent inserts a brand-new email in the happy-path flow.
Does Replit Agent handle openai 429 rate limits?
The openai SDK throws OpenAI.APIError on any non-2xx response. Each instance has a status property. Status 429 is the rate limit, and rate limits are not optional once a Replit app starts getting real traffic.
// Wrong way: what Replit Agent typically generates
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export async function summarize(text: string) {
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: `Summarize: ${text}` }],
});
return completion.choices[0].message.content;
}
// Right way: branches on openai status codes
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export async function summarize(text: string) {
try {
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: `Summarize: ${text}` }],
});
return completion.choices[0].message.content;
} catch (error) {
if (error instanceof OpenAI.APIError) {
if (error.status === 429) {
// Rate limited. Back off and retry, or queue the request.
throw new Error('OpenAI rate limit. Retry later.');
}
if (error.status === 401) {
// Bad API key. Stop retrying immediately.
throw new Error('OpenAI auth failed.');
}
}
throw error;
}
}
Browser self-test never burns enough tokens to hit a 429. Production does, often within hours of launch.
How do I scan or audit Replit Agent output in my Repl shell?
Run nark inside the Repl shell, save the report as JSON, and hand the file to Replit Agent. Agent reads JSON files better than it reads terminal scrollback, the structured format gives every violation a path and line number Agent can open directly, and the same file survives across multiple Agent turns so you can re-reference it without re-running anything.
The full loop, four steps:
-
Scan: In the Repl shell, run
npx nark --output nark-report.json. Nark walks your project's TypeScript AST, matches every imported npm package against its Nark Profile, and writes each missing try/catch plus each postcondition violation tonark-report.json. -
Prompt Agent: In Replit Agent chat, paste: "read nark-report.json and fix every violation it lists." Be literal. Agent does well with file-based instructions.
-
Agent fixes in place: Agent reads the JSON, opens each cited file at the cited line, wraps the call in a try/catch with branches on the documented error classes for that package (StripeCardError, PrismaClientKnownRequestError, OpenAI.APIError, etc.), and saves.
-
Verify zero: Re-run
npx nark(no--outputflag this time, just print to terminal). The violation count should drop to zero. If anything remains, paste the new output into Agent chat and ask for the missing fixes.
Why file-based and not copy/paste:
- Long reports survive intact. A 50-violation report does not fit cleanly into a chat prompt; a file does.
- JSON is the format Agent parses most reliably. Path, line, rule id, and Profile name are all structured fields, not free text.
- You can re-reference the same file across many Agent turns. "Look at violation 23 in nark-report.json" is unambiguous.
- The file lives in your Repl, so the next time you re-scan it gets overwritten with the latest state. No stale paste in chat history.
This is the same loop Caleb runs on his own Repls and on customer audits. It is not theoretical.
Why doesn't Replit's built-in Monitoring catch these?
Replit Deployments includes a Monitoring tab that surfaces logs and basic metrics: request counts, response times, error rates. It is helpful for "is the deploy alive" questions and "did latency spike at 3pm" questions.
It is not Sentry. It does not capture stack traces, group errors by type, alert on regressions, or tell you that PrismaClientKnownRequestError P2002 fired 47 times in the last hour. By the time Monitoring tells you something is wrong, the user has already seen the broken page.
That is the gap Nark fills, but it fills it on the other side of deploy. Nark runs before you ship the code. Monitoring runs after. Sentry runs after. Neither one prevents the bug from going live, they just tell you about it once a user trips it.
This is the standard pre-deploy / post-deploy split that every mature engineering team eventually adopts. Static analysis catches the class of bug before the deploy; error monitoring catches the instance after. You need both, and Replit's Monitoring is not a substitute for either.
Browser self-testing vs static analysis vs error monitoring
Three layers, each catches a different thing, none replace each other.
| Layer | What it catches | When it runs | Example tool |
|---|---|---|---|
| Browser self-test | Happy-path UI flow breaks | After build, in browser | Replit Agent 4 |
| Static analysis | Missing error handling around npm packages | Before deploy, in CI or shell | nark |
| Error monitoring | Crashes that already happened | After deploy, in production | Sentry |
Replit Agent's browser self-test is real and it does catch real problems, mostly visible ones. It does not catch invisible ones. A try/catch missing around stripe.paymentIntents.create() is invisible until a real card declines. Browser self-test never sees it.
Static analysis sees it because it reads the code. Nark walks the TypeScript AST, finds every awaited call, checks whether the call is wrapped, and flags the ones that are not. The check is purely structural, runs offline, and does not depend on the code actually executing.
Error monitoring sees it after the fact, which is the worst time. By then the user already had a bad experience and the bug is already on your incident timeline. Sentry is essential and you should still run it, but the goal is for Sentry to catch things Nark missed, not to be your primary safety net.
If you are shipping a real Repl, you want all three.
Could Replit ship this natively?
Yes, in principle. Replit owns the editor, the shell, the deploy pipeline, and the Agent. If they decided to ship a "Replit Audit" feature that encoded the documented failure modes for the top 200 npm packages, they could do it. Nothing about static analysis is proprietary or hard.
But their stated quality claim today is "Agent tests its own work" through browser self-testing. That is the entire pitch on the Agent product page. As long as that stays the pitch, dependency-aware error checking lives in a separate tool, and Nark is the most direct way to get it into a Repl today.
This is not a bash on Replit. The browser self-test is a real product that catches a real category of bug, and Replit has built it well enough to use it as their lead quality claim. Dependency-aware error checking is just a different category of bug, sitting on a different layer, and the platform that owns the IDE is not obligated to also own that layer. The whole point of "100+ integrations" is that other tools fill in around Replit. Nark is one of them.
If Replit ever ships native dependency-aware error checking, this gap closes and the article framing changes. Until then: run npx nark in your Repl shell.
Frequently Asked Questions
Do I need Sentry if I use Replit?
Yes. Replit's built-in Monitoring is logs and basic metrics, not Sentry-style stack-trace error tracking. Sentry catches the instance of a bug after it fires in production. Nark catches the class of bug before it ever ships. Run both: Nark in your Repl shell before deploy, Sentry in production after deploy. They sit on different sides of the deploy boundary and do not substitute for each other.
Is Replit Agent code production ready?
It is production ready for the visible UI flow Replit Agent's browser self-test exercises (page renders, form submits, route returns 200). It is not production ready for the invisible package failures (declined Stripe cards, duplicate Prisma inserts, openai rate limits) that the browser self-test never triggers. Before a real production deploy, run npx nark --tsconfig ./tsconfig.json in your Repl shell to flag every missing handler around the npm packages Agent imported.
Does Replit Agent wrap Stripe calls in try/catch?
No, not by default. Replit Agent will typically generate await stripe.paymentIntents.create() without any wrapper because its training distribution is dominated by minimal happy-path examples that omit error handling. The browser self-test passes because the Stripe test card succeeds. The first declined card in production crashes the route. Add the try/catch yourself or let npx nark flag the missing one before you ship.
What npm packages does nark check for in a Repl?
Nark ships 165+ Profiles covering the npm packages most likely to fail silently in a Repl: stripe, prisma, openai, @anthropic-ai/sdk, axios, pg, redis, mongoose, @aws-sdk/client-s3, twilio, sendgrid, resend, ioredis, and many more. Each Profile encodes the package's documented error classes and the postconditions that catch the most commonly missed handlers (e.g. PrismaClientKnownRequestError P2002 for duplicates, StripeCardError for declined cards, OpenAI.APIError status 429 for rate limits).
Try It Now
npx nark --tsconfig ./tsconfig.json
Nark scans 165+ npm packages for missing error handling, including stripe, prisma, openai, axios, and pg. It runs in any TypeScript project, including a Repl shell. To produce a JSON report you can hand back to Replit Agent for in-place fixes:
npx nark --output nark-report.json
Then in Replit Agent chat: "read nark-report.json and fix every violation it lists."