Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
All errors
Deployment

BadElement / Element type required / package.xml is malformed

Your `package.xml` (or `destructiveChanges.xml`) is invalid XML or references a metadata type the platform doesn't recognise. The error names the offending element. Validate the XML syntax, confirm the type names, and confirm the API version supports them.

Also seen asBadElement·package.xml is malformed·Invalid manifest·Element type is required

The deploy refuses with BadElement: Element type "AccountTrigger" must be followed by either attribute specifications, ">" or "/>". or package.xml is malformed. The CLI took five seconds to get to this error. The XML is hundreds of lines; the offending element is somewhere in the middle. The team huddles to find where.

What the platform validates

The Metadata API requires package.xml (and the related destructiveChanges.xml) to be valid XML conforming to a specific schema. The validator checks:

  • Well-formed XML. Every open tag has a matching close tag; attributes are quoted; entities are escaped.
  • Recognized element names. The <types> and <members> elements have specific semantics; misnamed elements are rejected.
  • Recognized metadata types in <name>. Each <types> block declares a metadata type like ApexClass, CustomObject, or LightningComponentBundle. The type must match a recognized value for the API version specified.
  • Valid API version. The <version> tag at the end must be a valid Salesforce API version (e.g., 59.0, 60.0).

If any check fails, the deploy stops with BadElement (for XML issues), Invalid manifest (for structural issues), or a specific message naming the offending element.

The broken example

A package.xml that mixes valid and invalid pieces:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>AccountTrigger</members>
        <members>OpportunityTrigger</members>
        <name>ApexClass</name>
    </types>
    <types>
        <members>MyCustomObject__c</members>
        <name>CustomObject</name>
    </types>
    <types>
        <members>SomeBundle
        <name>LightningComponentBundle</name>
    </types>
    <version>59.0</version>
</Package>

Three problems:

  1. AccountTrigger is named under <name>ApexClass</name> but triggers are a separate metadata type (ApexTrigger).
  2. The third <types> block has an unclosed <members> tag (missing </members>).
  3. (Depending on the API version) LightningComponentBundle should be LightningComponentBundle exactly; case matters.

The validator reports the first failure it encounters. The fix often takes multiple passes if the file has many issues.

The fix: validate XML first, then validate metadata types

Two sub-problems with two sub-fixes.

Validate well-formed XML. Use a standard XML validator (your editor probably has one built in; xmllint is the CLI option). The validator catches unclosed tags, unescaped ampersands, mismatched attributes.

xmllint --noout package.xml

A clean run means the file is well-formed. An error names the line and column of the issue.

Validate metadata types and names. The Salesforce CLI has sf project deploy preview that lints the manifest without actually deploying. It checks every type and member name against the platform's catalog and reports unknown ones.

sf project deploy preview --target-org production --manifest manifest/package.xml

The preview output shows what would deploy. If a member doesn't exist or a type is unrecognized, the preview names it.

The fixed example

A correct package.xml with the three issues resolved:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>AccountServiceHelper</members>
        <members>OpportunityCalculator</members>
        <name>ApexClass</name>
    </types>
    <types>
        <members>AccountTrigger</members>
        <members>OpportunityTrigger</members>
        <name>ApexTrigger</name>
    </types>
    <types>
        <members>MyCustomObject__c</members>
        <name>CustomObject</name>
    </types>
    <types>
        <members>SomeBundle</members>
        <name>LightningComponentBundle</name>
    </types>
    <version>59.0</version>
</Package>

The structure is well-formed, the types are correct (ApexClass and ApexTrigger are distinct), and the API version is current.

Common type-name mistakes

A pattern catches admins coming from package authoring tools that use slightly different conventions. The most common confusions:

What you might writeActual metadata type
TriggerApexTrigger
LWCLightningComponentBundle
AuraComponentAuraDefinitionBundle
WorkflowWorkflow (plus child types like WorkflowFieldUpdate)
EmailTemplateEmailTemplate
RecordTypeRecordType (but always with a parent CustomObject prefix in members)
LayoutLayout (members use ObjectName-LayoutName)

For child types (Layouts, RecordTypes, ValidationRules), the member naming convention is ObjectName-MemberName:

<types>
    <members>Account-Standard Layout</members>
    <name>Layout</name>
</types>

Forgetting the parent prefix produces a deploy error that names the member, not the type, which can be confusing.

API version mismatches

The <version>59.0</version> at the bottom tells the platform which API version's metadata catalog to validate against. Some metadata types were introduced in specific API versions. A package.xml that references a Spring '24 metadata type with <version>30.0</version> fails because the type wasn't recognized in API 30.

The fix is to bump the version to one that supports all the types you reference. New code should use a recent API version (60.0+ at the time of writing).

destructiveChanges.xml has its own rules

For deploys that delete metadata, destructiveChanges.xml lives alongside package.xml and lists what to remove:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>OldClass</members>
        <name>ApexClass</name>
    </types>
    <version>59.0</version>
</Package>

The same BadElement and Invalid manifest errors apply to destructiveChanges.xml. A malformed destructive manifest fails the entire deploy, including the additive package.xml.

For complex destruction operations (deleting many components in a specific order), destructiveChangesPre.xml (runs before the additive) and destructiveChangesPost.xml (runs after) give finer control. Each follows the same schema.

Using sf project retrieve start to generate a baseline

If you're building a package.xml from scratch and want a reference, retrieve a known-good source set:

sf project retrieve start --target-org production --metadata 'ApexClass,ApexTrigger,LightningComponentBundle,CustomObject'

The CLI generates a package.xml listing every retrieved component. Use it as a starting point and edit down.

Validation in CI

The best moment to catch a malformed manifest is at PR time, not deploy time. Add a CI step that runs:

xmllint --noout manifest/package.xml manifest/destructiveChanges.xml
sf project deploy preview --target-org test-org --manifest manifest/package.xml

The xmllint step catches structural problems. The sf project deploy preview step catches type and name problems. Both run in seconds. Failing PRs with a clear error message saves the deploy team's time.

When the error message points at the wrong line

XML errors sometimes name a line that's far from the actual mistake. The most common case: an unclosed tag early in the file shifts the parser's position so the error appears to be in a later element that's actually valid.

When the error message points at a line that looks fine, look upward in the file for unclosed tags. The validator scans forward and reports the first divergence; the cause is usually before the reported position.

Build-time generators that produce package.xml

Some teams generate package.xml programmatically (a script reads the source directory and emits the manifest). The script's correctness becomes critical: a bug that emits malformed XML breaks every deploy.

Best practice: the generator validates its output with xmllint before writing. A failing validation aborts the script. The team never deploys a broken manifest.

A subtle case: BOM at the start of the file

Some Windows editors save UTF-8 files with a Byte Order Mark (BOM) at the start. The BOM is invisible in most editors but the Metadata API rejects it as invalid XML preamble. The error message: Invalid manifest, with the cursor pointing at column 0 of line 1.

Fix: save the file as "UTF-8 without BOM" (a common option in most editors). Or use a Linux/Mac command:

sed -i '1s/^\xEF\xBB\xBF//' manifest/package.xml

The command strips the BOM if present. Re-run the deploy.

Common workflow: piecing together a manifest from multiple sources

Larger teams often combine manifests from multiple sources: one team's components, another team's components, a shared library. Each source has its own package.xml. Concatenating them naively produces a single file with multiple <Package> roots, which is invalid XML.

The right approach is to merge by <types> blocks: a single <Package> root, multiple <types> children, one <version> at the end. Tools like sf project list-source-files and various third-party Salesforce DevOps tools handle the merge automatically.

For ad-hoc merges, a small script that parses each input and emits a merged output is reliable. Don't hand-merge by copy-paste; the structural rules are easy to break.

Member naming for collections

Some metadata types group members. Profile, for example, contains many sub-permissions, and a Profile's metadata file is large. In package.xml, you reference the Profile by its name; the platform retrieves or deploys the whole bundle.

<types>
    <members>Standard User</members>
    <members>System Administrator</members>
    <name>Profile</name>
</types>

For wildcards (where supported), use *:

<types>
    <members>*</members>
    <name>ApexClass</name>
</types>

The wildcard means "every component of this type in the source." Not all types support wildcards; the docs list which do. When wildcards are allowed, they simplify retrieves significantly.

The connection to source format

Modern Salesforce DX projects use source format (one folder per component instead of one big metadata file). The CLI translates between source format and the older Metadata API format. package.xml is the API-format declaration; the source folders are the developer-facing layout.

When a deploy fails on a malformed manifest, the source files themselves are usually fine; the issue is in the generated or hand-written package.xml. The CLI commands (sf project deploy start) auto-generate the manifest from source. If you're writing the manifest by hand, the auto-generated version from sf project list-source-files is a useful template.

When the deploy still fails after fixing the XML

A well-formed manifest can still fail the deploy for non-XML reasons:

  • The named component exists in source but isn't deployable in the target org (license restriction, edition mismatch).
  • A dependency on the component isn't in the manifest (you reference a custom field but didn't include its parent CustomObject).
  • A deploy-time validation rule rejects the component (test coverage too low for ApexClass, validation rule formula too complex).

These produce different error messages than BadElement. If you've fixed the XML and still see errors, read the new message carefully; it's pointing at a different layer.

A short XML primer for the malformed cases

For developers new to XML, the rules that produce the most BadElement errors:

  • Every tag must close. <members>foo</members>, not <members>foo.
  • Tags must nest properly. <a><b></b></a>, not <a><b></a></b>.
  • Attribute values must be quoted. <elem name="foo">, not <elem name=foo>.
  • Reserved characters (<, >, &, ", ') inside text must be entity-escaped (&lt;, &gt;, &amp;, &quot;, &apos;).
  • The document has exactly one root element.

Salesforce package.xml follows all of these, plus the schema-specific rules about which elements can appear where. The combination is strict but small; a few minutes with the schema produces lasting fluency.

Migration tooling worth knowing

For teams managing many package.xml files (one per release, one per feature), three tools save time:

  • sf project list-source-files: lists every component in source, ideal for generating manifests.
  • sf project deploy preview: validates the manifest without deploying.
  • Tools like Gearset, Copado, and Flosum maintain change-set-style manifests with UI-based editing.

The CLI tools are free and ship with the Salesforce DX setup. Third-party tools cost money but pay off for teams managing complex multi-environment promotion pipelines.

Further reading from Salesforce

Related dictionary terms

Share this fix

Share on LinkedInShare on X

Related Deployment errors