draftOrderCreate rejects one valid Japanese mobile number with “Phone number in shipping address is invalid”

Hi all — I’m trying to understand how phone-number validation works in the Admin GraphQL draftOrderCreate mutation.

Context

We programmatically create draft orders as part of a fulfillment-related flow.

The draft order is created from an existing Shopify order. We copy the original order’s shipping address into draftOrderCreate.shippingAddress, including:

  • countryCode: JP
  • provinceCode
  • zip
  • city
  • address1
  • phone

Error

For one specific Japanese mobile number, draftOrderCreate returns:

{
“userErrors”: [
{
“field”: null,
“message”: “Phone number in shipping address is invalid”
}
]
}

The phone number is in Japanese local mobile format:

text 090xxxxxxxx

It has 11 digits, no hyphens, and no +81 country prefix.

Why this is confusing

This does not appear to be a general formatting issue.

  1. The same store successfully creates draft orders with other Japanese mobile numbers in the same local format.
  2. The issue seems isolated to one specific number.
  3. countryCode: JP is included.
  4. The number is valid according to common phone-number validation libraries such as libphonenumber.
  5. The original Shopify order went through Checkout successfully with this exact phone number.
  6. On another test/development store, draftOrderCreate with the same local-format number succeeds.

So the issue appears to be specific to one Japanese mobile number in one store context, while the same number is accepted by Checkout and by another store.

Questions

  1. What validation does draftOrderCreate apply to shippingAddress.phone?
  2. Is the validation based on libphonenumber, or does it check anything beyond format?
  3. Are there any store-level settings that can affect phone validation for draft orders?
  4. Why might a phone number accepted by Checkout later be rejected by Admin GraphQL draftOrderCreate?
  5. Is Japanese local format supported when countryCode: JP is provided, or should we always normalize to E.164 format before calling draftOrderCreate?

Environment

  • Admin API version: 2025-07
  • Mutation: draftOrderCreate
  • Country code: JP

Any insight into the validation logic or possible differences between Checkout and Admin GraphQL validation would be greatly appreciated. Thank you!

@dk-dev The immediate fix is to normalize the phone to +819012345678 (E.164) before passing it to draftOrderCreate.
You should apply this normalization universally to all numbers you copy from orders into draft orders - don’t rely on local-format coercion working even when it has worked before for other numbers.
It’s an undocumented behavior, not a feature.
Here are more detailed answers.

  1. What validation does draftOrderCreate apply?

E.164 format check + Shopify’s internal phone range/validity check (not pure libphonenumber)

  1. Is it libphonenumber-based?

Shopify uses its own validator — likely derived from libphonenumber but a different version/configuration. Don’t assume parity.

  1. Store-level settings affecting validation?

Store region and fraud settings can influence behavior, but format requirements are platform-wide.

  1. Why does Checkout accept it?

Checkout uses a more permissive validator optimized for buyer UX. Admin GraphQL is stricter.

  1. Should you always use E.164?

Yes. E.164 is the only documented, reliable format for MailingAddressInput.phone.

@Andrii_Hudimov
Thank you for the detailed explanation — that makes sense.

For this specific case, the request succeeded when we retried it a few hours later without changing the phone number or order data. So it may have been a temporary or context-specific validation issue.

However, I understand that relying on local-format phone numbers is not safe, even if it works in some cases. We’ll update our implementation to normalize phone numbers to E.164 before passing them to draftOrderCreate.

Thanks again for the clear guidance.