# Nullable fields explicitly marked

- **Pattern:** `ab-000362` (`api-design.contract-quality.nullable-explicit`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000362
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000362)

## Why it matters

When a field typed as `string` returns `null` at runtime, consumers get a type error or a silent coercion depending on their language. When some endpoints omit missing fields and others include them as `null`, every consumer must guard against both `undefined` and `null` for every optional field. This is the most common source of unexpected `Cannot read properties of null` errors in client applications. iso-25010:2011 compatibility.interoperability requires that the schema truthfully represent what the API sends — nullability is a core part of that contract.

## Severity rationale

Medium because undeclared nullability causes runtime type errors in consumers and forces defensive null-guarding throughout client code without enabling direct security exploits.

## Remediation

Mark nullable fields explicitly in both your TypeScript types and your OpenAPI schema. Choose one approach for missing data — always include with `null`, or always omit — and document it:

```ts
// TypeScript -- explicit nullability:
interface UserResponse {
  id: string            // always present
  name: string          // always present
  avatarUrl: string | null   // explicitly nullable
  bio: string | null         // explicitly nullable
}
```

```yaml
# OpenAPI -- nullable fields:
UserResponse:
  type: object
  required: [id, name]
  properties:
    avatarUrl: { type: string, nullable: true }
```

Consistency between "return `null`" and "omit the field" is non-negotiable — consumers cannot handle both reliably.

## Detection

- **ID:** `nullable-explicit`
- **Severity:** `medium`
- **What to look for:** Examine response objects for fields that can be `null`. Check whether nullability is explicitly documented in the schema (OpenAPI `nullable: true` or union type with `null`, GraphQL non-null `!` vs nullable, TypeScript `| null` annotations, Pydantic `Optional` types). Look for fields that sometimes return a value and sometimes return `null` or are absent entirely -- consumers need to know which fields are reliably present. Also check: does the API return `null` for missing fields, or omit them entirely? Consistency matters.
- **Pass criteria:** Count all fields that can return `null` across response types. Nullable fields are explicitly marked in the schema or type definitions. The API consistently either returns `null` for empty optional fields or omits them (one approach, not both). Consumers can determine from the schema which fields may be null. At least 90% of nullable fields must have explicit nullability annotations.
- **Fail criteria:** Fields that can be `null` are not marked as nullable in the schema or types. The API inconsistently returns `null` for some missing fields and omits others. Consumers discover nullability through runtime errors.
- **Skip (N/A) when:** No schema or type definitions exist (covered by other checks). Also skip if all response fields are always non-null by design.
- **Detail on fail:** Identify the ambiguity (e.g., "`User.avatarUrl` is typed as `string` but returns null when no avatar is set. `Order.shippedAt` is sometimes absent from the response and sometimes null. Schema does not mark either field as nullable."). Max 500 chars.
- **Remediation:** Make nullability explicit in your schema and types:

  ```ts
  // TypeScript -- explicit nullability:
  interface UserResponse {
    id: string           // always present
    name: string         // always present
    avatarUrl: string | null  // explicitly nullable
    bio: string | null        // explicitly nullable
  }
  ```

  ```yaml
  # OpenAPI -- nullable fields:
  UserResponse:
    type: object
    required: [id, name]
    properties:
      id: { type: string }
      name: { type: string }
      avatarUrl: { type: string, nullable: true }
  ```

  Choose one approach for missing data: always include the field with `null`, or always omit it. Document which approach you use.

## External references

- iso-25010 compatibility.interoperability

Taxons: code-quality

HTML version: https://auditbuffet.com/patterns/ab-000362
