Summary
On a record detail page, a Field.address value renders as a stringified JSON object instead of a formatted address. The same field renders correctly in the create/edit dialog, so this is specific to the detail page's read renderer.
Observed on protocol ^17.0.0-rc.1 in a zh-CN console.
Evidence
The decisive comparison is same record, same page, same field group — one address field next to one location field:
| field | type | detail page (read) |
|---|
billing_address | Field.address | ❌ {"street":"中策路 1 号","city":"杭州",…} |
office_location | Field.location | ✅ 📍 30.2741, 120.1551 |
So the detail page's display renderer has a location formatter and lacks an address one, falling through to stringifying the object.
Meanwhile the create/edit dialog renders the same billing_address correctly as Street / City / State / ZIP / Country inputs.
This matches the shipped console bundle: the input registry carries both address: and location:; the display registry the detail page uses does not carry address.
The detail page's inline edit mode also shows the JSON.
Scope
Type-level, not object-specific. Confirmed by writing a value into a second object's address field through the API (crm_quote.billing_address) and seeing the same JSON rendering; reverted afterwards.
Any app with a populated Field.address on a detail page is affected.
Why there is no reasonable app-side workaround
Downstream consumers of ours evaluated and rejected each of these:
- Change the field to
text — destroys the structured value and breaks derivations that read sub-fields (in our case a billing_address.country projection that territory sharing rules match on), and loses the sub-field inputs that currently work. - Add a mirrored display-only field — puts two addresses on the page that can drift apart.
- Author detail-page sections — that changes where the value comes from, not the renderer that formats it.
Expected
The detail page's display registry resolves address the way it resolves location, rendering a formatted postal address.
Related
Same family as #4854 (view/report/dataset label translation path) in that it is a renderer-registry gap on one surface while a sibling surface handles it correctly, though the mechanism is different — this one is a missing formatter, not a missing i18n lookup.
Summary
On a record detail page, a
Field.addressvalue renders as a stringified JSON object instead of a formatted address. The same field renders correctly in the create/edit dialog, so this is specific to the detail page's read renderer.Observed on protocol
^17.0.0-rc.1in a zh-CN console.Evidence
The decisive comparison is same record, same page, same field group — one
addressfield next to onelocationfield:billing_addressField.address{"street":"中策路 1 号","city":"杭州",…}office_locationField.location📍 30.2741, 120.1551So the detail page's display renderer has a
locationformatter and lacks anaddressone, falling through to stringifying the object.Meanwhile the create/edit dialog renders the same
billing_addresscorrectly as Street / City / State / ZIP / Country inputs.This matches the shipped console bundle: the input registry carries both
address:andlocation:; the display registry the detail page uses does not carryaddress.The detail page's inline edit mode also shows the JSON.
Scope
Type-level, not object-specific. Confirmed by writing a value into a second object's address field through the API (
crm_quote.billing_address) and seeing the same JSON rendering; reverted afterwards.Any app with a populated
Field.addresson a detail page is affected.Why there is no reasonable app-side workaround
Downstream consumers of ours evaluated and rejected each of these:
text— destroys the structured value and breaks derivations that read sub-fields (in our case abilling_address.countryprojection that territory sharing rules match on), and loses the sub-field inputs that currently work.Expected
The detail page's display registry resolves
addressthe way it resolveslocation, rendering a formatted postal address.Related
Same family as #4854 (view/report/dataset label translation path) in that it is a renderer-registry gap on one surface while a sibling surface handles it correctly, though the mechanism is different — this one is a missing formatter, not a missing i18n lookup.