Summary
sf project convert source double-escapes XML numeric character references inside <formula>, <defaultValue>, and (by extension) <errorConditionFormula> tags. A source file containing ' (valid XML for ') becomes &#39; in the generated .object. The result deploys a broken formula string to the org and also causes server-side Syntax error. Found '&' failures in pipelines that consume the converted MDAPI.
Steps To Reproduce
Minimal project (no org needed). One field with a formula that uses both & (string concat) and ' (single-quote).
sfdx-project.json:
{
"packageDirectories": [{"path": "force-app", "default": true}],
"sourceApiVersion": "59.0"
}
force-app/main/default/objects/Foo__c/Foo__c.object-meta.xml:
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<deploymentStatus>Deployed</deploymentStatus>
<label>Foo</label>
<pluralLabel>Foos</pluralLabel>
<nameField><label>Name</label><type>Text</type></nameField>
<sharingModel>ReadWrite</sharingModel>
</CustomObject>
force-app/main/default/objects/Foo__c/fields/Bar__c.field-meta.xml:
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Bar__c</fullName>
<externalId>false</externalId>
<formula>LOWER(Name & ' ' & Name)</formula>
<formulaTreatBlanksAs>BlankAsZero</formulaTreatBlanksAs>
<label>Bar</label>
<required>false</required>
<type>Text</type>
<unique>false</unique>
</CustomField>
Run:
sf project convert source --source-dir force-app --output-dir mdapi
grep formula mdapi/objects/Foo__c.object
Expected result
The emitted <formula> should preserve valid XML entities that already existed in the source (or re-encode them losslessly):
<formula>LOWER(Name & ' ' & Name)</formula>
Actual result
The numeric character references get escaped a second time, producing:
<formula>LOWER(Name & &#39; &#39; & Name)</formula>
After the server-side XML decode, the formula body stored on the field becomes literally:
LOWER(Name & ' ' & Name)
…which is not a valid formula. In a real pipeline running sf project deploy start against an org (source-format deploy, REST transport), this surfaces as MDAPI component failures like:
- 30 component failures in one deploy, all
Syntax error. Found '&' (line:col)
- Every failing component is a
CustomField with a <formula> / <defaultValue> that contains ', or a ValidationRule with <errorConditionFormula>. Examples from a real deploy:
CustomField Action_Item__c.Due_Status__c Found '&' (174:13)
CustomField Activity__c.Action_Verb__c Found '&' (1784:13)
CustomField Favorite__c.Type__c Found '&' (103:13)
ValidationRule Activity_Template__c.Activity_Type_Field_Required Found '&' (1021:22)
CustomField SiteTraker_Object__mdt.History_Object_Name__c (defaultValue <code>'Project_History__c'</code>) Found '&' (309:13)
Additional information
- Reproduces identically on
@salesforce/cli@2.132.13 and @salesforce/cli@2.132.14 (same @salesforce/source-deploy-retrieve 12.32.8 / 12.32.9 respectively). I originally suspected the 2.132.14 publish based on pipeline timing, but the local repro shows the same double-encoding on both, so the regression may predate that.
sf project convert source and sf project deploy start share the source→MDAPI path via @salesforce/source-deploy-retrieve; the bug manifests wherever that path is exercised.
System Information
Shell: bash on macOS (Darwin 24.6.0)
{
"architecture": "darwin-arm64",
"cliVersion": "@salesforce/cli/2.132.14",
"nodeVersion": "node-v21.7.0",
"osVersion": "Darwin 24.6.0",
"shell": "bash",
"pluginVersions": [
"@salesforce/cli 2.132.14 (core)",
"deploy-retrieve 3.24.33 (core)"
]
}
Summary
sf project convert sourcedouble-escapes XML numeric character references inside<formula>,<defaultValue>, and (by extension)<errorConditionFormula>tags. A source file containing'(valid XML for') becomes&#39;in the generated.object. The result deploys a broken formula string to the org and also causes server-sideSyntax error. Found '&'failures in pipelines that consume the converted MDAPI.Steps To Reproduce
Minimal project (no org needed). One field with a formula that uses both
&(string concat) and'(single-quote).sfdx-project.json:{ "packageDirectories": [{"path": "force-app", "default": true}], "sourceApiVersion": "59.0" }force-app/main/default/objects/Foo__c/Foo__c.object-meta.xml:force-app/main/default/objects/Foo__c/fields/Bar__c.field-meta.xml:Run:
Expected result
The emitted
<formula>should preserve valid XML entities that already existed in the source (or re-encode them losslessly):Actual result
The numeric character references get escaped a second time, producing:
After the server-side XML decode, the formula body stored on the field becomes literally:
…which is not a valid formula. In a real pipeline running
sf project deploy startagainst an org (source-format deploy, REST transport), this surfaces as MDAPI component failures like:Syntax error. Found '&' (line:col)CustomFieldwith a<formula>/<defaultValue>that contains', or aValidationRulewith<errorConditionFormula>. Examples from a real deploy:CustomField Action_Item__c.Due_Status__c Found '&' (174:13)CustomField Activity__c.Action_Verb__c Found '&' (1784:13)CustomField Favorite__c.Type__c Found '&' (103:13)ValidationRule Activity_Template__c.Activity_Type_Field_Required Found '&' (1021:22)CustomField SiteTraker_Object__mdt.History_Object_Name__c (defaultValue <code>'Project_History__c'</code>) Found '&' (309:13)Additional information
@salesforce/cli@2.132.13and@salesforce/cli@2.132.14(same@salesforce/source-deploy-retrieve 12.32.8/12.32.9respectively). I originally suspected the 2.132.14 publish based on pipeline timing, but the local repro shows the same double-encoding on both, so the regression may predate that.sf project convert sourceandsf project deploy startshare the source→MDAPI path via@salesforce/source-deploy-retrieve; the bug manifests wherever that path is exercised.System Information
Shell: bash on macOS (Darwin 24.6.0)
{ "architecture": "darwin-arm64", "cliVersion": "@salesforce/cli/2.132.14", "nodeVersion": "node-v21.7.0", "osVersion": "Darwin 24.6.0", "shell": "bash", "pluginVersions": [ "@salesforce/cli 2.132.14 (core)", "deploy-retrieve 3.24.33 (core)" ] }