GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is now available as the fastest, most cost-efficient Gemini Image modelOMNIFLASH — Gemini Omni Flash comes to the API in public preview for building custom, dynamic video workflowsAGENTS — Managed Agents arrives in the Gemini API, running autonomous agents in secure Google-hosted Linux sandboxesFILESEARCH — File Search now supports multimodal search via gemini-embedding-2, with media_id for visual citationsWEBHOOKS — Event-driven Webhooks replace polling for the Batch API and long-running operationsDEPRECATE — Older image generation models are deprecated and shut down on Aug 17, so plan your migrationNANOLITE — Nano Banana 2 Lite is now available as the fastest, most cost-efficient Gemini Image modelOMNIFLASH — Gemini Omni Flash comes to the API in public preview for building custom, dynamic video workflowsAGENTS — Managed Agents arrives in the Gemini API, running autonomous agents in secure Google-hosted Linux sandboxesFILESEARCH — File Search now supports multimodal search via gemini-embedding-2, with media_id for visual citationsWEBHOOKS — Event-driven Webhooks replace polling for the Batch API and long-running operationsDEPRECATE — Older image generation models are deprecated and shut down on Aug 17, so plan your migration
Articles/API / SDK
API / SDK/2026-07-13Advanced

When an Optional Field Comes Back Three Ways: Null, Empty String, and Missing Key in Gemini Structured Output

Optional fields in Gemini structured output drift between null, empty string, and a missing key, and downstream code breaks in three different ways. Here is how I collapse all three into one shape using nullable in responseSchema and a post-output normalization gate, with numbers from a nightly batch.

Gemini API182structured output6responseSchema5data normalizationbatch processing2

Premium Article

Last week the nightly batch I run as an indie developer had quietly died before dawn. It is a small pipeline: classify App Store reviews with Gemini structured output, then write the summary and an improvement tag into Firestore. The stack trace pointed at a single line that upper-cased suggested_tag, with Cannot read properties of null.

A job that had run fine the day before fell over because the model's output wobbled slightly. The cause was that one optional field was arriving in three different shapes: null, an empty string, and sometimes with the key missing entirely. I was already passing a responseSchema, so why was this happening? Fixing it took work at both the entry and the exit of the pipeline. Here is how it settled down.

What "three shapes" actually looks like

With the same schema and the same prompt, an optional field does not settle on one representation. Here are the three forms suggested_tag (an optional improvement tag) came back as, pulled from real logs.

CaseActual outputType in JavaScriptNaive code behavior
Value present"suggested_tag": "dark-mode"stringWorks
Null"suggested_tag": nullnull (object)Throws on .toUpperCase()
Empty string"suggested_tag": ""string (length 0)Injects an empty tag
Missing keykey absentundefinedSlips past later branches

The tricky part is that all three mean the same thing — "there is no tag" — yet they break downstream code in different ways. Null throws, the empty string looks harmless while it seeds meaningless data, and the missing key sails through a conditional and resurfaces later as a separate, harder-to-locate bug. That asymmetry in how they fail is exactly what made the root cause hard to isolate.

Why an optional field becomes three shapes

A responseSchema constrains the type and structure of a field, but it does not decide, on its own, how "no value" should be represented. That was the assumption I had wrong.

First, a field you leave out of required can be dropped entirely at the model's discretion. Second, even inside required, if you do not declare nullable, the model fills "no value" with an empty string here and null there, following whatever it happened to generate. Third, pinning field order with propertyOrdering stabilizes order, not value representation — those are two separate axes. Order stability is a different problem, which I covered in stabilizing field order with propertyOrdering; this drift lives one layer deeper.

So a schema alone cannot shrink three shapes into one. You narrow the drift at the entry point (schema design) and fold what remains at the exit (post-output normalization). It takes both.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Trace why optional fields drift across null, empty string, and missing key by looking at responseSchema behavior
Use nullable and required together to narrow the drift at the entry point
A normalization gate that folds the three shapes into one, with the missing-value rate from 3,200 reviews
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

API / SDK2026-06-19
Generate Japanese and English in One Structured Call to Stop Term Drift
Generating Japanese and English versions separately makes terminology drift article by article. Pair both languages in one Gemini 3.5 Flash structured-output call, pin a glossary, and detect drift mechanically — with measured results.
API / SDK2026-06-12
Designing a Nightly Batch That Survives a Gemini API Outage — Three Layers of Defense
This week's widespread Gemini outage cost my nightly batch three hours of work. Here is how I rebuilt it with three layers of defense: classified retries, a model fallback chain, graceful degradation, plus idempotency keys and a catch-up queue.
API / SDK2026-05-21
When responseSchema enum returns unexpected values — debugging Gemini API
Why Gemini API sometimes returns values outside the enum you defined in responseSchema, and the three-layer workaround I use in production for my wallpaper app classification pipeline.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →