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 likeApexClass,CustomObject, orLightningComponentBundle. 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:
AccountTriggeris named under<name>ApexClass</name>but triggers are a separate metadata type (ApexTrigger).- The third
<types>block has an unclosed<members>tag (missing</members>). - (Depending on the API version)
LightningComponentBundleshould beLightningComponentBundleexactly; 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 write | Actual metadata type |
|---|---|
Trigger | ApexTrigger |
LWC | LightningComponentBundle |
AuraComponent | AuraDefinitionBundle |
Workflow | Workflow (plus child types like WorkflowFieldUpdate) |
EmailTemplate | EmailTemplate |
RecordType | RecordType (but always with a parent CustomObject prefix in members) |
Layout | Layout (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 (<,>,&,",'). - 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
Related Deployment errors
ALREADY_IN_PROCESS: another deployment is in progress
DeploymentAn org can run only one deployment at a time. Your deploy is queued behind a deployment someone (or some automation) already started. Wait f…
ApexUnitTestClassShouldHaveAsserts / ApexBadCrypto / Code Analyzer violations blocking deploy
DeploymentSalesforce's open-source code scanners (PMD-Apex, Salesforce Code Analyzer) found rule violations in your codebase. They don't block deploys…
Average test coverage across all Apex Classes and Triggers is XX%, at least 75% required
DeploymentA production deploy of Apex requires at least 75% line coverage *org-wide*, and 100% on triggers (including triggers that aren't part of you…
Cannot change field type from <type1> to <type2> via the API
DeploymentSalesforce restricts which field type changes are allowed in a deploy. Many type transitions (Number to Text, Picklist to Lookup, Text to Lo…
Cannot delete this <component>: it is referenced by other components
DeploymentYou're trying to delete or refactor a metadata component (custom field, Apex class, page, flow, etc.) that other metadata still references. …