"It Works in Test, But the Field Is Empty in Production": Diagnosing Silent Discovery Field Mapping
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
58m ago
This is one of the most frustrating classes of bug in Discovery and integration work, precisely because nothing throws an error. Your test instance shows the field populated correctly. Production runs the exact same integration, the exact same transform, and the field just sits empty. No failed transaction, no red status, nothing in the logs pointing at the problem. Here's how to actually track this down instead of staring at identical-looking configurations wondering why one works and one doesn't.
Why this happens, and why it's silent
Field mapping failures that only show up in production almost always come down to a data difference between environments, not a configuration difference. The transform map, the field mapping rule, the script, they're identical. What's different is the actual data flowing through them, and platform field mapping logic is generally built to skip a field quietly rather than throw an error when something unexpected happens, because a hard failure on every edge case would break far more integrations than it protects.
That design choice is reasonable at the platform level, but it means the burden is on you to go find where the skip happened, because the platform isn't going to tell you.
The most common root causes
Reference field resolution failing silently. If your field mapping resolves a reference field (say, mapping an incoming string to a cmdb_ci reference by looking up a matching record), and no matching record exists in production, most reference field lookups simply leave the field empty rather than erroring out. In test environments, seed data conveniently already has the matching record. In production, on a real, larger dataset, that match might not exist yet, might exist under a slightly different value, or might be genuinely ambiguous with multiple matches. Check whether your mapping is doing a reference lookup, and if so, test it against production-scale, production-shaped data, not clean test fixtures.
Case sensitivity and whitespace differences. Test data is usually hand-entered and clean. Production data comes from real source systems and is messy: extra whitespace, inconsistent casing, encoding differences. A field mapping that does an exact string match will work perfectly against clean test values and fail against a production value that's functionally identical to a human but not to a string comparison.
Conditional field mapping rules with untested branches. If your field mapping rule includes conditional logic (map field A only when condition X is true), it's easy to test the branch you expect to hit and never exercise the other branches. Production data is where you first encounter a case that falls into a branch nobody actually validated. This is especially common with source systems that have more variety in their data than your test scenarios anticipated.
Payload size or field length truncation. Some source fields carry more data in production than in test (a longer description, a more detailed name), and if the target field has a length constraint that test data never approached, production data can get silently truncated or rejected depending on how the field is configured. This looks like a mapping bug but is actually a schema constraint issue.
Different transform run order or coalesce behavior. If your transform map coalesces on a field, and production has multiple source records that could match the same target record in a way test data doesn't replicate, you can end up with fields getting overwritten by a later run in an order that wasn't anticipated. The field looks empty not because it was never set, but because a subsequent transform run cleared or overwrote it.
How to actually diagnose it
Don't start by re-reading the field mapping configuration; you'll read it the same way you did when you wrote it, and it'll look correct because it is correct for the case you had in mind. Instead:
- Pull the actual raw payload from production for a record where the field is empty, and compare it directly against a payload from test where the field populated correctly. Look for differences in exact structure, not just "does the value seem present."
- Check the transform history / import log for that specific record, not just the overall job status. A job can report success while an individual field mapping silently skipped.
- Reproduce the production payload in a lower environment by replaying the exact raw data, not by manually re-entering what you think the data looks like. The gap is almost always in something you'd never think to manually type in yourself.
- Check for reference field ambiguity specifically if the field in question is a reference type. This is disproportionately the cause in Discovery and connector-driven CMDB population.
The pattern to build going forward
The real fix for this category of bug isn't finding this one instance, it's changing how you test going forward. Test environments that only ever see clean, hand-crafted data will keep producing this exact failure mode in different fields, over and over, because the test data is fundamentally not representative of what production actually sends. Where possible, seed test and staging environments with anonymized samples of real production payloads rather than idealized examples, specifically so these mismatches surface before go-live instead of after.
Takeaway
A field that's empty in production but populated in test is very rarely a mapping logic bug. It's almost always a data shape difference that your test data never exercised, combined with the platform's tendency to skip a mapping quietly rather than fail loudly. Go to the raw payload first, every time, before touching the configuration.
Has anyone found a good way to systematically capture production payload variety into lower environments without duplicating live data wholesale? That balance between realistic test data and sensible data handling is something I'm still refining.