Nark + CodeRabbit: AI Code Review Meets Deterministic Dependency Checking
By Nark Team
CodeRabbit is an AI-powered PR reviewer that reads your diff with an LLM, understands intent, and gives contextual feedback on code logic, style, and structure. Nark is a deterministic scanner that checks whether your TypeScript code handles the specific errors your npm dependencies throw at runtime. CodeRabbit is probabilistic and broad. Nark is deterministic and narrow. They do not compete. They complement.
Quick Answer: CodeRabbit reviews your code. Nark reviews your dependencies. CodeRabbit uses LLMs to understand what your code is doing. Nark uses the TypeScript compiler and 160+ package Profiles — covering axios, prisma, stripe, redis, and more — to check whether your code handles what your dependencies can throw. Run both:
npx nark --tsconfig ./tsconfig.json
What Does CodeRabbit Do?
CodeRabbit is an AI code review tool that integrates into your GitHub or GitLab PR workflow. When you open a PR, CodeRabbit reads the diff, understands the context across files, and leaves review comments. It uses large language models to reason about your code the way a human reviewer would.
What CodeRabbit catches:
- Logic errors and potential bugs in your business logic
- Code style issues and readability concerns
- Missing edge case handling that a human reviewer might flag
- Cross-file impact analysis ("this change in
auth.tsaffects the middleware inrouter.ts") - Suggestions for better patterns, naming, and structure
What makes CodeRabbit different from a linter:
- It understands intent, not just syntax
- It reads the full PR context, not individual files in isolation
- It learns from your team's feedback over time
- Each review is generated fresh by an LLM
CodeRabbit is good at catching the kind of issues a senior engineer would catch during code review. It reads your code, reasons about it, and tells you what looks wrong.
What Does Nark Do?
Nark is a Nark Profile scanner. It parses your TypeScript code using the TypeScript compiler (tsc) and checks it against a library of 160+ Profiles. Each Profile is a YAML specification that encodes what a specific npm package can throw at runtime, what error types it uses, and what handling your code needs.
What Nark catches:
axios.get()without try-catch (throwsAxiosErroron any non-2xx response)prisma.user.create()without catchingPrismaClientKnownRequestError(throws P2002 on duplicate email)zod.parse()without try-catch (throwsZodErroron invalid input)jwt.decode()used withoutjwt.verify()(returns unverified claims)stripe.charges.create()without catchingStripeCardError(unhandled card declines)redis.get()without an.on('error')handler (process crash on connection failure)
What makes Nark different from an AI reviewer:
- It is deterministic. Same code, same result, every run.
- It does not read your code for intent. It checks against a known specification.
- The Profiles are built from package changelogs, documentation, and CVE databases.
- It finds violations that require package-specific knowledge, not general code reasoning.
How Are They Different?
| CodeRabbit | Nark | |
|---|---|---|
| Approach | AI/LLM (probabilistic) | TypeScript compiler + YAML Profiles (deterministic) |
| Scope | Entire PR: logic, style, structure, intent | Dependency error handling only |
| Knowledge source | LLM training data + your repo context | 160+ curated Profiles from changelogs and CVEs |
| Consistency | Different runs can produce different feedback | Same input, same output, every time |
| Cross-file awareness | Yes. Understands how changes propagate across files | Yes, within a TypeScript project's dependency graph |
| Learning | Adapts from team feedback over time | Profiles are versioned and updated from package releases |
| What it reviews | Your code's logic and quality | Whether your code handles what your dependencies throw |
| Trigger | PR opened or updated | CLI scan or CI check |
| False positive handling | Dismiss comment, CodeRabbit learns | Inline // nark-ignore annotation |
The key distinction: CodeRabbit reasons about your code. Nark checks your code against a specification. These are fundamentally different operations.
What Would CodeRabbit Miss That Nark Catches?
CodeRabbit is a general-purpose AI reviewer. It does not carry package-specific knowledge about what every npm dependency throws, what error codes it uses, or what the changelog says about breaking changes. Here are two real findings from scanning open-source TypeScript projects.
Example 1: 100 unguarded zod.parse() calls in civitai/civitai
civitai/civitai is an open-source model-sharing platform with over 1.2 million users. Nark found approximately 100 API routes that call zod.parse() on request input without a try-catch:
export default PublicEndpoint(async function handler(req, res) {
const { modelId, modelVersionId } = querySchema.parse(req.query);
// ...
});
zod.parse() throws a ZodError when input does not match the schema. Without a catch, every malformed request returns a 500 Internal Server Error instead of a 400 Bad Request. Public endpoints are affected. No authentication required to trigger it.
Would CodeRabbit catch this? Maybe some of the instances. An AI reviewer might flag a bare .parse() in a single route and suggest adding error handling. But finding all 100 instances across api/admin/, api/mod/, api/webhooks/, server/, and shared/orchestrator/ requires systematic scanning, not probabilistic review. The violations are spread across 40+ files in different directories. A human reviewer (or AI reviewer) seeing one route at a time in a PR would not have the cross-codebase visibility to say "this same pattern is unhandled in 99 other places."
Nark catches all 100 because it checks every call to .parse() in the project against the zod Profile. Same scan, same result, every time.
Example 2: jwt.decode() without jwt.verify() in NangoHQ/nango
NangoHQ/nango is an open-source OAuth platform with 6,000+ stars. Nark found 6 instances of jwt.decode() used to extract claims from access tokens without calling jwt.verify() first.
The shared utility wraps the call:
export function decode(token: string): Record<string, any> | null {
try {
return jwt.decode(token) as Record<string, any>;
} catch {
return null;
}
}
jwt.decode() base64-decodes the JWT payload without verifying the signature. The function is named just decode(). There is no indication at the call site that the returned claims are unverified. It is called in OAuth post-connection hooks for Microsoft Teams, OneDrive, Xero, and Sellsy to extract tenant IDs from access tokens.
Would CodeRabbit catch this? Unlikely. The code is syntactically correct. The function works as written. The issue is not a logic error in the code. The issue is that jsonwebtoken's decode() function does not verify signatures, and the jsonwebtoken documentation explicitly warns against using decoded claims for authorization decisions. This is package-specific knowledge from the jsonwebtoken changelog and security documentation. An AI reviewer would need to know the difference between jwt.decode() and jwt.verify() at the library API level, not at the code logic level.
Nark catches this because the jsonwebtoken Profile specifies that decode() return values must be followed by a verify() call. The Profile was built from the package's own documentation and known security patterns.
What Would Nark Miss That CodeRabbit Catches?
Nark does not review your business logic, code style, naming, architecture, or anything outside the scope of dependency error handling. Here are things CodeRabbit catches that Nark does not:
- Race conditions in your async flow
- Off-by-one errors in your pagination logic
- Missing null checks on your own functions (not dependency calls)
- Naming issues ("this variable is misleading")
- Architectural concerns ("this controller is doing too much")
- Security issues in your code like SQL injection from string concatenation (Semgrep also catches this)
- Dead code or unreachable branches
Nark is deliberately narrow. It only checks one thing: whether your code handles what your npm dependencies throw. If your code does not call any npm packages, Nark has nothing to say.
Can You Run Both in CI?
Yes. They occupy different stages of the pipeline.
CodeRabbit runs as a PR integration. When a PR is opened, CodeRabbit posts review comments directly on the diff. It operates at the PR level.
Nark runs as a CI check. Add it alongside your linter and test suite:
# .github/workflows/ci.yml
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx eslint .
- run: npx nark --tsconfig ./tsconfig.json
- run: npm test
CodeRabbit reviews the PR for code quality and logic. Nark checks for unhandled dependency errors. ESLint catches language-level issues. Your test suite verifies behavior. Each tool has a lane.
When Would You Choose One Over the Other?
You would not. They solve different problems.
Use CodeRabbit when you want AI-powered code review that catches logic bugs, suggests improvements, and acts as a second pair of eyes on every PR. It replaces or augments human code review.
Use Nark when you want deterministic, reproducible checks that your code handles the runtime errors your npm dependencies can throw. It runs alongside your linter and test suite as a CI gate.
Use both when you want comprehensive coverage: an AI reviewer for code quality and a deterministic scanner for dependency completeness.
The question is not "CodeRabbit or Nark." The question is whether your CI pipeline checks for unhandled dependency errors at all. Most do not. Adding Nark takes one line.
Frequently Asked Questions
Does CodeRabbit check npm package error handling?
CodeRabbit reviews code at the logic and intent level. It may occasionally flag missing error handling if the pattern is obvious. But it does not carry structured knowledge of what specific npm packages throw, what error codes they use, or what their changelogs say about error handling requirements. That is Nark's domain.
Is Nark an AI tool?
No. Nark uses the TypeScript compiler to parse your code and checks it against YAML Profile specifications. There is no LLM involved. The Profiles are written by humans from package documentation, changelogs, and CVE databases. The scan is deterministic.
Do they produce conflicting results?
No. They check different things. CodeRabbit might comment "consider adding error handling here" on a PR. Nark will report "no try-catch block found for axios.get() — AxiosError will crash the application" as a CI check failure. The feedback is complementary, not contradictory.
Can Nark replace CodeRabbit?
No. Nark only checks dependency error handling. It does not review code logic, style, architecture, or anything else. It is not a code reviewer. It is a dependency completeness checker.
Can CodeRabbit replace Nark?
Not reliably. CodeRabbit might catch some dependency error handling issues through general AI reasoning. But it cannot guarantee it will catch all instances, it cannot guarantee the same result on repeated runs, and it does not carry the package-specific Profile knowledge that Nark uses (160+ packages, built from changelogs and CVEs).
Try It Now
npx nark --tsconfig ./tsconfig.json
Run both. CodeRabbit reviews your code. Nark reviews your dependencies. npx nark.