0Pricing
Claude Architect · Lesson

Required vs Optional/Nullable Fields

Never require a field that may be absent.

Required vs Optional/Nullable Fields is a free Claude Architect lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Claude Architect learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

The Core Rule

Structured output with tool_use and a JSON Schema eliminates syntax errors and lets you enforce required fields. But that power has a sharp edge.

The exam-critical rule for this lesson: mark a field required only if it is always present. Never require a field that may be absent.

Why? When a field is required, the model must emit a value for it. If the source data doesn't actually contain that value, the model has no choice but to fabricate one to satisfy the schema. A required field is a promise the model will keep even when it shouldn't.

Why Required Forces Fabrication

A JSON Schema's required array is a hard constraint, not a hint. The model cannot return a structurally valid object while omitting a required key.

Consider extracting a customer's phone_number from a support email that never mentions a phone number. If phone_number is required, the model must produce something — and a plausible-looking but invented number is worse than no number at all, because nothing downstream can tell it apart from a real one.

The fix is structural: make optional fields optional, so the model can legitimately leave them out when the information is absent.

A Schema That Invites Fabrication

Here is an extraction tool that marks every field as required. The email below has no phone number — yet the schema forces the model to invent one.

This is the anti-pattern. Read required carefully: it lists fields that may genuinely be missing from real inputs.

tool = {
    "name": "extract_contact",
    "description": "Extract contact details from a support email.",
    "input_schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"},
            "phone_number": {"type": "string"},
        },
        # BAD: phone_number is often absent, but it is required here
        "required": ["name", "email", "phone_number"],
    },
}

The Fix: Require Only the Guaranteed

Keep in required only the fields that are always present. Everything that may be absent stays out of required — the model can then omit it honestly.

Notice name and email stay required because every support ticket has them, while phone_number drops out of the list.

tool = {
    "name": "extract_contact",
    "description": "Extract contact details from a support email.",
    "input_schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"},
            "phone_number": {"type": "string"},
        },
        # GOOD: only the always-present fields are required
        "required": ["name", "email"],
    },
}

Optional vs. Nullable: Two Different Tools

There are two ways to let a field be "missing", and they mean different things:

  • Optional — the key is simply omitted from required. The model may leave the key out of the object entirely.
  • Nullable — the key is always present but its type allows null, signalling "this slot was checked and found empty."

Optional answers "did the model report on this field at all?" Nullable answers "the model looked, and the value is explicitly absent." Choose nullable when a downstream consumer needs every key present for a stable shape.

Expressing Nullable in JSON Schema

To make a field nullable, allow null as one of its types. With structured outputs you typically express this with anyOf (a supported keyword) combining the real type and null.

Here phone_number is always emitted as a key, but its value is null when the email contains no number — an honest "empty", not a fabricated digit string.

"phone_number": {
    "anyOf": [
        {"type": "string"},
        {"type": "null"}
    ],
    "description": "Customer phone number, or null if none is stated in the email."
}

Nullable Still Needs an Honest Instruction

A nullable type permits null, but the model still decides when to use it. Make the intent explicit in the field description: tell the model to return null rather than guess.

This pairs the structural guarantee (the type allows null) with a behavioural one (the description says when to use it). The schema defines the shape; the description steers the judgment.

"discount_code": {
    "anyOf": [{"type": "string"}, {"type": "null"}],
    "description": "The promo code the customer mentioned. Return null if no code is present — do not invent or infer one."
}

Enums Plus an 'Other' Escape Hatch

The same fabrication risk appears with enums. If a field must be one of a fixed set of values and the real input doesn't match any of them, a strict enum forces the model to pick the closest wrong answer.

The exam-recommended pattern for extensibility: include an "other" value in the enum plus a free-text detail field. This gives the model an honest place to land when reality exceeds your enum — instead of misclassifying.

"category": {
    "type": "string",
    "enum": ["billing", "technical", "account", "other"]
},
"category_detail": {
    "anyOf": [{"type": "string"}, {"type": "null"}],
    "description": "Free-text description used when category is 'other'; otherwise null."
}

Retry Won't Rescue an Absent Value

When validation fails, retry-with-feedback is powerful — you resend the original document, the model's wrong output, and the exact validation error to fix format, structural, or arithmetic mistakes.

But retry does not help when the information is simply absent from the source. If the phone number isn't in the email, no amount of re-prompting will conjure a correct one. The right design lets the field be absent in the first place — required-and-missing is a schema bug, not a transient error to retry.

Self-Correction Detects, Schema Prevents

For values that should be present and verifiable, a complementary technique is self-correction: extract both a calculated_total and a stated_total so a mismatch surfaces a discrepancy you can catch.

But self-correction detects errors in present data; it cannot validate a field that was never in the source. The first line of defense against fabrication is still the schema itself: don't require what may be absent. Use Pydantic-style validation on the result to enforce these invariants in code.

from pydantic import BaseModel
from typing import Optional

class Invoice(BaseModel):
    invoice_id: str            # always present → required
    po_number: Optional[str]   # may be absent → optional / nullable
    calculated_total: float
    stated_total: float        # compare the two to detect discrepancies

Distinguish Empty From Failure

One more architect-grade distinction: a valid empty result ("the email has no phone number") is not the same as an access failure ("the extraction tool errored").

A nullable field cleanly represents the first case. Don't model a genuine absence as an error to retry, and don't silently suppress a real failure as null. Make the schema say which is which: null for legitimately empty, a separate error path for access failures. Clear, structured signals downstream beat ambiguous ones.

Quick Check: Optional Field Design

Apply the rule to a realistic extraction scenario.

Recap: Never Require the Maybe-Absent

Key takeaways:

  • Require only always-present fields. Requiring a possibly-absent field forces the model to fabricate a value.
  • Optional = key may be omitted; nullable = key always present, value may be null. Pick nullable when consumers need a stable key set.
  • Pair nullable types with a description that says "return null if absent — don't guess."
  • For closed value sets, add an "other" enum value plus a free-text detail field for extensibility.
  • Retry-with-feedback fixes format/structural/arithmetic errors, not absent information. Self-correction detects discrepancies in present data, not missing fields.
  • Keep a valid empty result distinct from an access failure — never silently suppress either.

Frequently asked questions

Is the “Required vs Optional/Nullable Fields” lesson free?

Yes — the full text of “Required vs Optional/Nullable Fields” is free to read here on the web, and the Claude Architect course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Claude Architect course, upgrade to CoddyKit PRO.

What will I learn in “Required vs Optional/Nullable Fields”?

Never require a field that may be absent. You practise Claude Architect with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Claude Architect?

No prior experience is required. Claude Architect on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Required vs Optional/Nullable Fields” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Claude Architect lesson?

Yes. Every Claude Architect lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. tool_use for Guaranteed Structure
  2. Designing a JSON Schema
  3. Required vs Optional/Nullable Fields
  4. Enums with 'other' for Extensibility
← Back to Claude Architect