Two fields both called state, and only one of them will take TN
With State and Country/Territory Picklists on, Lead.State holds Tennessee and Lead.StateCode holds TN. A Flow copying the wrong one into a restricted picklist looked correct, deployed clean, and would have failed every enquiry with an address on it.
A homeowner calls about a broken spring, gives an address, and the enquiry gets filed. Behind that, automation is supposed to create the property record the technician will eventually be dispatched to. It would have failed. Not on some enquiries — on every single one that had an address on it, which is all of them.
The cause was one line that copied a field called state into another field called state.
Two fields, one name, different contents
Doorvana’s org has State and Country/Territory Picklists enabled. That is the right call for anything that will be reported on or routed by geography, and it is close to mandatory before you start matching addresses across objects. What it does not do is replace the address fields you already had. It adds new ones next to them.
| Field | Type | Holds |
|---|---|---|
Lead.State | Text | Tennessee |
Lead.StateCode | Picklist | TN |
Lead.Country | Text | United States |
Lead.CountryCode | Picklist | US |
Both are populated. Both are visible. On the record page they render as one address block, so
a user sees a single state, picks it once, and has no idea two fields just got written. The
same pairing exists on every standard address on the platform — BillingState /
BillingStateCode, ShippingState / ShippingStateCode, MailingState / MailingStateCode.
Where the property record comes from
Under this org’s model, a service address is not a field on the Account. It is a standard
Location record, joined to the household by AssociatedLocation, for the reasons set out in
the household account write-up. Standard
lead conversion does not create that Location, so a Flow does.
The Location carries plain address fields rather than a VisitorAddressId lookup —
benchmarked, not argued about — and one of them is
Site_State__c. To stop TX, Texas and tx from being three different states in every
report, Site_State__c is a restricted picklist on a US_State global value set, and that
value set is keyed on the two-letter code.
So the destination accepts TN. It accepts nothing else that means Tennessee.
The line that was obviously correct
force-app/main/default/flows/Create_Location_From_Lead.flow-meta.xml
<!-- before -->
<recordCreates>
<name>Create_Site_Location</name>
<inputAssignments>
<field>Site_State__c</field>
<value><elementReference>$Record.State</elementReference></value>
</inputAssignments>
</recordCreates> Read that as a sentence. Put the lead’s state on the location’s state field. It is what you
would write, it is what a reviewer reads, and it is wrong. $Record.State resolves to
Tennessee. Site_State__c will only take TN.
The fix is four characters.
force-app/main/default/flows/Create_Location_From_Lead.flow-meta.xml
<!-- after -->
<inputAssignments>
<field>Site_State__c</field>
<value><elementReference>$Record.StateCode</elementReference></value>
</inputAssignments> What it would have cost
Worth being precise about the blast radius, because it is larger than it sounds.
The Flow creates the Location. The Location is what an Opportunity points at, what an
AssociatedLocation junction hangs off, and ultimately what a Work Order is scheduled
against. A failed Location create does not produce a lead with a slightly wrong state. It
produces a converted lead with no property record at all, and a Field Service chain with
nothing to dispatch to.
Every enquiry carrying an address is every enquiry. There is no subset here that still works.
How it was caught
One fabricated enquiry, followed all the way through.
Not a unit test of the Flow. Not a review of the metadata. One invented record — a homeowner, a street address, a request type — created at the top of the funnel and then followed through every automation it triggered until it either produced the whole downstream chain or stopped. It stopped.
The same test found the same mistake in a second place that nobody had exercised yet. Both were fixed in the same pass, which is the part that makes end-to-end testing pay: the bug is rarely alone, because whoever wrote it wrote it more than once.
Why review could never have caught it
This is the honest version of the lesson, and it is not “be more careful.”
Both fields are called state. Both contain a state. They sit side by side on the same screen and differ by four characters in the API name. The assignment reads as a correct English sentence. Nothing in Flow Builder warns you that the destination is restricted, nothing tells you the source is the label rather than the code, and the metadata deploys clean because nothing about it is invalid — it is only wrong at runtime, with real data, in one direction.
The tooling has all the information required to flag this and does not.
What to actually do about it
Three things, in order of how much they are worth.
Map from the Code fields whenever the destination is code-keyed. StateCode and
CountryCode, not State and Country. If you have enabled State and Country/Territory
Picklists, treat the text fields as display artefacts and stop reading them in automation.
Make the destination restricted on purpose. A restricted picklist on a global value set is
what turned this from a silent data-quality rot into a loud runtime failure. An unrestricted
picklist would have accepted Tennessee, stored it happily, and left a property base where
some rows say TN and some say Tennessee and no report over geography is trustworthy again.
The error is the feature.
Grep the org for the other one. If a mapping like this exists once, assume it exists
twice. Searching the retrieved source for elementReference>$Record.State< takes a second and
answers the question properly, which reading Flows in the UI does not.
The whole fix was four characters. Finding it was one fake customer and twenty minutes.