Hi @Ramesh_B1
I believe that what you’re seeing is the native checkout field’s “touched” validation state lingering after a programmatic update. applyShippingAddressChange does write the value to the shipping address state, but it doesn’t clear the field-level UI error that Shopify’s checkout already rendered when the buyer touched/blurred that input. The next validation cycle (i.e. submit) will re-evaluate against the real value, so the buyer can complete checkout — but the inline error stays visible until then, which is the UX issue you’re describing.
A few things to check and try:
1. Confirm the change actually succeeded. applyShippingAddressChange returns a ShippingAddressChangeResult you should inspect:
const result = await applyShippingAddressChange({
type: 'updateShippingAddress',
address: { city: areaLabel },
});
if (result.type === 'error') {
console.warn('Address update failed:', result.errors);
}
If result.type === 'error', the value never got written and the native error is correct.
2. Guard with cart instructions. The change is silently rejected on accelerated checkouts (Apple Pay, Google Pay, Meta Pay) or when the cart instruction is off:
const instructions = useInstructions();
if (!instructions.delivery?.canSelectCustomAddress) return;
See Updating to 2025-01 for the instructions check.
3. Hide / disable the native city field. Since you’re driving city selection with your own dropdown, the cleanest pattern is to render your dropdown as the only city UI for the buyer. The native field’s required-error appears because the buyer interacted with it before your value landed. If you’re using purchase.checkout.shipping-address.render-before/render to inject your dropdown, pair it with messaging that the city is set via the dropdown, so the buyer never focuses the underlying field. There’s no public API to clear a native field’s error state from an extension — that’s the gap here.
4. Confirm Level 2 protected customer data scope. city requires Level 2 access in the Partner Dashboard. Without it, the write is rejected even though the call appears to resolve.
Check the above and if you’re still seeing this issue let me know!