Architect expression for phone number formatting failing on +1XXXXXXXXXX

Why does this setting in my Architect Data Action consistently return null or malformed output when trying to convert a E.164 string like +15551234567 into (555) 123-4567?

expression:
 type: "function"
 name: "formatPhoneNumber"
 args:
 - "{{contact.phoneNumber}}"
 - "(XXX) XXX-XXXX"

The function call isn’t throwing an error, but the result is empty. Am I missing a specific library import or is there a regex-based alternative expression that works reliably for this pattern?

As far as I remember, the Architect expression builder doesn’t support custom JS libraries like that, so you’ll need to use the built-in format function or a Data Action with a simple regex replace instead. Try switching to a JavaScript action in your flow to handle the string manipulation directly.

Warning: The formatPhoneNumber function isn’t a native Architect expression, which is why your output is null.

You need to drop that custom function approach entirely since it doesn’t exist in the runtime.

  • use replace with a regex like \+(\d)(\d{3})(\d{3})(\d{4}) to capture groups
  • map it to ($2) $3-$4 directly in the expression builder
4 Likes

expression:
type: “function”
name: “replace”
args:

  • “{{contact.phoneNumber}}”
  • “\+([0-9])([0-9]{3})([0-9]{3})([0-9]{4})”
  • “($1) $2-$3”
the `formatPhoneNumber` function doesn't exist in the standard runtime context. you're hitting null because the expression engine can't resolve that name. use the native `replace` function instead.

make sure to double-escape the backslashes in the regex pattern. architect expressions parse the string before passing it to the regex engine, so `\+` becomes `+` which matches any character. you need `\\+` to match the literal plus sign.

also, check the input string. if `contact.phoneNumber` contains spaces or dashes already, the regex won't match. add a `replace` step first to strip non-numeric characters except the leading plus. this approach is cleaner than injecting a custom JS action for simple formatting. keeps the flow declarative.
1 Like

problem: formatPhoneNumber isn’t a native function. it’s undefined in the expression engine, so it returns null.

got the regex mostly right, but the escaping in Architect YAML is tricky. you need to be careful with backslashes. if you’re using a Data Action with type: "function" and name: "replace", the regex pattern needs proper escaping for the JSON/YAML parser.

here’s a working config for the Data Action:

expression:
 type: "function"
 name: "replace"
 args:
 - "{{contact.phoneNumber}}"
 - "\\+(\\d)(\\d{3})(\\d{3})(\\d{4})"
 - "($1) $2-$3"

note the double backslashes \\ for the capturing groups. if you’re doing this directly in a flow step (not a Data Action), the escaping might differ slightly depending on how the UI serializes it.

also, keep in mind this regex assumes US/Canada numbers (+1). if you get international numbers, this will break or return the original string. i usually add a fallback in my local mock API tests to catch malformed inputs before they hit the live environment.

if you want to be safer, chain a trim first.

expression:
 type: "function"
 name: "trim"
 args:
 - "{{contact.phoneNumber}}"

then pass that result into the replace. helps avoid issues with leading spaces from the IVR or CRM integration.

i’ve seen cases where the regex engine in Architect is strict about the + sign. make sure the input is actually E.164. if it’s just 15551234567 (no plus), the regex won’t match. you might need two replace steps or a more complex regex to handle both cases.

just test it in your local compose stack with a mock endpoint. easier than waiting for the next flow deployment to fail.