Fairy
Resources

How to Avoid: Missing null/empty handling

August 11, 2026 · 8-minute read · Fairy

The short answer

To prevent missing null/empty handling in AI-generated code, always check for null, undefined, and empty arrays before accessing properties or iterating. AI models often generate the happy path without defensive checks. Use optional chaining, guard clauses, and explicit empty-state handling. Automated review tools can flag patterns like .find(), [0], and .length access on potentially null values.

How to Prevent Missing Null/Empty Handling in AI-Generated Code

Missing null and empty handling is one of the most common logic bugs in AI-generated code. When AI writes code, it typically generates the happy path—the flow where data exists, arrays have elements, and API calls succeed. This creates code that works perfectly in demos but crashes in production when a user doesn't exist, a search returns no results, or an optional field is missing.

The fix requires systematic defensive programming: check for null, undefined, and empty arrays before accessing properties or iterating. This article explains why AI produces this pattern, how to detect it during review, and the correct patterns to prevent these crashes.

Why AI Models Skip Null Checks

AI code generation models learn from vast repositories of existing code. The problem is that most training examples demonstrate successful operations. When someone writes a tutorial or example, they show users.find(u => u.id === userId).name—not the defensive version that handles the case where the user doesn't exist.

This creates a systematic bias. The model sees thousands of examples of direct property access and relatively few examples of defensive null handling. When generating code, it completes the pattern it has seen most frequently.

Three factors amplify this problem:

Context window limitations. AI models work with limited context. They might not see the upstream code that could return null, so they assume the value exists.

Prompt focus on functionality. When you ask AI to "get the user's name from the database," it focuses on the retrieval logic, not the failure modes. The prompt emphasizes what should happen, not what could go wrong.

Training data quality. Production code with proper error handling is often in private repositories. Public code—tutorials, examples, Stack Overflow answers—frequently omits edge cases for clarity.

The Most Dangerous Patterns

Missing null handling appears in predictable forms. Recognizing these patterns helps you catch bugs before they reach production.

Array .find() Without Null Checks

The .find() method returns undefined when no element matches. AI-generated code frequently chains property access directly:

// Dangerous: crashes if user not found
const userName = users.find(u => u.id === targetId).name;

// Also dangerous: assignment then access
const user = users.find(u => u.id === targetId);
sendEmail(user.email); // crashes if user is undefined

Direct [0] Array Access

Assuming arrays have elements is another common failure:

// Dangerous: crashes on empty results
const firstResult = searchResults[0].title;

// Also dangerous: in async contexts
const latestOrder = await db.orders.findMany({ where: { userId } });
processOrder(latestOrder[0].items); // crashes if user has no orders

Chained Property Access on API Responses

External APIs and database queries can return null or partial data:

// Dangerous: assumes nested structure exists
const city = response.data.user.address.city;

// Dangerous: assumes relationship is loaded
const authorName = post.author.profile.displayName;

Length Checks After Potentially Undefined Values

A subtle variant where the null check happens too late:

// Dangerous: .filter() is safe, but result could be empty
const activeUsers = users.filter(u => u.active);
const firstActive = activeUsers[0]; // undefined if none active
console.log(firstActive.email); // crash

Detection Signals During Code Review

When reviewing AI-generated code, look for these patterns that signal potential null handling issues:

Signal terms to watch:

Questions to ask for each occurrence:

  1. What returns this value? Can it ever be null/undefined?
  2. What returns this array? Can it ever be empty?
  3. Is there an upstream check that guarantees existence?
  4. What should happen if the value doesn't exist?

The fourth question is critical. Sometimes the correct behavior is to throw an error. Sometimes it's to return a default value. Sometimes it's to skip the operation entirely. AI rarely makes this decision explicitly—it just assumes the data exists.

The Correct Patterns

Guard Clauses for Required Values

When null represents an error condition, fail fast with a clear message:

const user = users.find(u => u.id === targetId);
if (!user) {
  throw new Error(`User not found: ${targetId}`);
}
// Now safe to use user.name, user.email, etc.
sendEmail(user.email);

This pattern is superior to optional chaining when the value must exist for the operation to make sense.

Optional Chaining for Graceful Degradation

When missing data is acceptable and should result in undefined:

// Returns undefined if any part of the chain is null
const city = response?.data?.user?.address?.city;

// Combine with nullish coalescing for defaults
const displayName = user?.profile?.name ?? 'Anonymous';

Explicit Empty Array Handling

Always verify arrays have elements before accessing by index:

const results = await search(query);

if (results.length === 0) {
  return { message: 'No results found' };
}

// Now safe to access results[0]
const topResult = results[0];

For operations that should work on the first element if it exists:

const firstResult = results[0];
if (firstResult) {
  processResult(firstResult);
}

// Or use optional chaining
const title = results[0]?.title ?? 'Untitled';

Defensive Destructuring

Provide defaults during destructuring to handle missing properties:

// Dangerous
const { user: { name, email } } = await getProfile(userId);

// Safe: defaults at each level
const { user = {} } = await getProfile(userId) ?? {};
const { name = 'Unknown', email = null } = user;

Before and After: A Complete Example

Consider this AI-generated function that processes order data:

Before: Missing Null Handling

async function getOrderSummary(orderId) {
  const order = await db.orders.findUnique({
    where: { id: orderId },
    include: { items: true, customer: true }
  });
  
  const subtotal = order.items.reduce((sum, item) => 
    sum + item.price * item.quantity, 0
  );
  
  return {
    orderId: order.id,
    customer: order.customer.email,
    items: order.items.length,
    subtotal: subtotal,
    shipping: order.shippingAddress.city
  };
}

This function has multiple crash points:

After: Proper Defensive Handling

async function getOrderSummary(orderId) {
  const order = await db.orders.findUnique({
    where: { id: orderId },
    include: { items: true, customer: true }
  });
  
  if (!order) {
    throw new Error(`Order not found: ${orderId}`);
  }
  
  const items = order.items ?? [];
  const subtotal = items.reduce((sum, item) => 
    sum + (item.price ?? 0) * (item.quantity ?? 0), 0
  );
  
  return {
    orderId: order.id,
    customer: order.customer?.email ?? 'No customer email',
    items: items.length,
    subtotal: subtotal,
    shipping: order.shippingAddress?.city ?? 'No shipping address'
  };
}

The corrected version:

Integrating Null Checks Into Your AI Workflow

Catching missing null handling requires review at multiple points.

Prompt Engineering

Include defensive requirements in your prompts:

Write a function to get user profile data. 
Handle the case where the user doesn't exist.
Handle the case where optional fields (bio, avatar) are null.

This doesn't guarantee correct handling, but it increases the probability.

Automated Review

Tools like Fairy Scout automatically flag patterns that signal missing null handling. The signals—.find(, [0], property chains on dynamic data—can be detected statically before code reaches production.

Type Systems

TypeScript with strict null checks catches many of these issues at compile time:

// With strictNullChecks, this is a compile error
const user = users.find(u => u.id === targetId);
console.log(user.name); // Error: 'user' is possibly 'undefined'

If you're generating TypeScript, ensure strict mode is enabled and don't allow // @ts-ignore comments without review.

Integration Tests for Edge Cases

Write tests specifically for null/empty scenarios:

test('handles non-existent user', async () => {
  await expect(getOrderSummary('fake-id'))
    .rejects.toThrow('Order not found');
});

test('handles order with no items', async () => {
  const result = await getOrderSummary(emptyOrderId);
  expect(result.items).toBe(0);
  expect(result.subtotal).toBe(0);
});

Related Error Handling Patterns

Missing null handling often occurs alongside other error handling gaps. AI-generated code may also silently swallow errors in retry logic or return undefined instead of throwing on failures. These patterns share the same root cause: the model optimizes for the happy path.

When reviewing for null handling, also check that:

For production AI deployments, systematic code verification catches these patterns before they cause outages.

Summary

Missing null and empty handling is a predictable failure mode in AI-generated code. AI models produce happy-path code because that's what dominates their training data. The fix is systematic: recognize the signal patterns (.find(, [0], property chains), ask what should happen when data doesn't exist, and apply the appropriate defensive pattern—guard clauses for required values, optional chaining for graceful degradation, and explicit empty checks for arrays.

Automated detection tools can flag these patterns during review, but understanding why they occur helps you prompt AI more effectively and review its output more efficiently. The goal isn't to eliminate AI from your workflow—it's to verify that the code AI produces handles the real-world cases where data isn't perfect.

Frequently asked questions

Why does AI-generated code often miss null checks?

AI models optimize for the common case shown in training data. Most code examples demonstrate successful operations, not edge cases. The model completes the pattern it sees most often, which rarely includes defensive null handling.

What are the most common null handling bugs in AI code?

The most frequent issues are accessing properties on potentially null values from .find() operations, assuming arrays always have elements with [0] access, and calling methods on undefined return values. These cause runtime crashes when the expected data doesn't exist.

How can I automatically detect missing null checks?

Look for signal patterns in code review: .find() without subsequent null checks, direct [0] array access, and .length checks after operations that might return undefined. Static analysis tools and AI code reviewers can flag these patterns before deployment.

Should I use optional chaining or explicit null checks?

Use optional chaining (?.) for property access chains where undefined is an acceptable fallback. Use explicit null checks with early returns or error throwing when null represents an invalid state that should halt execution.


Have AI-generated work you’d want verified? Connect with a Fairy → or run a free check with Scout.

More resources