The resource ... is not allowed by API version <X>
Your sf CLI (or the metadata API call) is using an API version older or newer than what the requested resource supports. Either upgrade the CLI, change the project's `sourceApiVersion`, or use a feature available in the version you're on.
Also seen asresource not allowed by version·API version mismatch·Resource not allowed·INVALID_VERSION
A release engineer kicks off the CI deployment on a Friday afternoon. The script runs sf project deploy start against the staging org. The pipeline returns The resource /services/data/v55.0/tooling/deployments is not allowed by API version 55.0. Other pipelines on other branches deploy fine. The engineer compares the failing job to the working one and the difference is the project's sourceApiVersion. The team needs to understand how API versions flow through the CLI and how to keep them aligned.
What the platform is checking
Every Salesforce API call carries an API version. The version determines which endpoints exist, which fields are returned, which behaviors apply, and which deprecations are in effect. The CLI assembles requests using either an explicit version flag, a project-level sourceApiVersion, an org-level default, or the CLI binary's bundled default.
When the CLI sends a request to an endpoint that does not exist in the requested version, the platform returns The resource ... is not allowed by API version <X>. The endpoint might exist in newer versions (the request was downgraded) or it might exist in older ones (a deprecated endpoint that was removed). The fix is to align the API version with the endpoint's availability.
The error is precise about the endpoint and version. The CLI does not always make it obvious which version flag produced the request, so diagnosis requires understanding the CLI's version resolution order.
The resolution order is. First, an explicit --api-version (or older --apiversion) flag on the command. Second, the sourceApiVersion in sfdx-project.json. Third, the org-api-version value in sf config. Fourth, the CLI binary's compiled-in default.
A pipeline that worked yesterday and fails today usually has a mismatch in one of these layers. Either the CLI was upgraded and changed its default, or the project file was edited, or the org's default was reset, or a flag was added or removed.
The broken example
A sfdx-project.json file with a stale API version:
{
"packageDirectories": [
{ "path": "force-app", "default": true }
],
"name": "salesforce-app",
"namespace": "",
"sfdcLoginUrl": "https://login.salesforce.com",
"sourceApiVersion": "55.0"
}
The project was last updated when API version 55.0 was current. The deployment script runs sf project deploy start. The CLI assembles the request at version 55.0 because the project file says so. The endpoint /services/data/v55.0/tooling/deployments was deprecated in version 58.0 in favor of a new metadata API path. The platform refuses the call.
A second shape: a CI pipeline pins the CLI to an older version with npm install -g @salesforce/cli@2.x.y. The bundled defaults use a version that no longer supports a feature the pipeline relies on, such as a metadata type added in a newer release.
A third shape: a developer manually sets --api-version 60.0 on the command line. The org runs API version 62.0 generally but the developer's call uses 60.0. A field added in 61.0 is missing from the response. The deploy succeeds but the resulting record has a null where the developer expected a value.
Why API versions matter beyond endpoint availability
Endpoint availability is the most visible symptom but not the only one. Field availability, default field values, query behavior, and metadata serialization formats all depend on the API version.
A SOQL query that uses a relationship field added in version 60.0 returns an error when called against version 58.0. A Lightning component bundle's lwc:if syntax requires version 56.0 or later in the component's metadata declaration; deploying with an older sourceApiVersion produces parse errors.
Picklist values returned via REST in version 50.0 include all values regardless of the user's permissions; in version 52.0 and later, the response filters to values the user can access. Code that depends on the older behavior breaks when the API version is bumped.
Every Salesforce release notes document includes an "API Version Changes" section. Reading it before a deploy that touches CLI versions saves time.
The fix, three paths
Bump the project to a current API version. The most common cure. Salesforce supports an N-3 versioning policy: the current release plus the previous three are supported. As of API version 62.0 (Spring '26), versions 59 through 62 are first-class. Older versions still work but cannot use features introduced in newer ones.
{
"sourceApiVersion": "62.0"
}
After the change, run sf project deploy validate to confirm the deploy works at the new version. Some endpoint behaviors change between versions, so the validation catches regressions.
Pin the CLI to a recent version in CI. Keep the CLI roughly aligned with the org's API version. The CLI's own defaults track the platform's release cadence, so a recent CLI usually defaults to a current API version.
# .github/workflows/deploy.yml
steps:
- name: Install Salesforce CLI
run: npm install -g @salesforce/cli@latest
Avoid pinning to specific minor versions that may be missing features. Track the major version (2.x) and let the CLI auto-update to the latest patch.
Pass an explicit --api-version flag for commands that have version-specific behavior. When a single command needs to override the project default, pass the flag.
sf data query --query "SELECT Id FROM Account" --api-version 62.0
The override is local to the command. The project file remains the source of truth for general deploys.
The fixed example
A CI workflow that explicitly aligns versions:
name: Deploy to Staging
on:
push:
branches: [staging]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Salesforce CLI
run: npm install -g @salesforce/cli@latest
- name: Confirm CLI Version
run: sf --version
- name: Authenticate to Org
run: |
echo "$SF_AUTH_URL" | sf org login sfdx-url \
--sfdx-url-stdin \
--alias staging \
--set-default
env:
SF_AUTH_URL: ${{ secrets.SF_AUTH_URL_STAGING }}
- name: Validate Deploy
run: sf project deploy validate --target-org staging --test-level RunLocalTests
- name: Deploy
if: success()
run: sf project deploy start --target-org staging --test-level RunLocalTests
The workflow installs the latest CLI, logs its version for auditing, and uses the version in sfdx-project.json for all deploys. No commands pin --api-version because the project's sourceApiVersion is current.
A matching sfdx-project.json:
{
"packageDirectories": [
{ "path": "force-app", "default": true }
],
"name": "salesforce-staging",
"sfdcLoginUrl": "https://test.salesforce.com",
"sourceApiVersion": "62.0"
}
Edge case: API versions in metadata files
Individual Apex classes, triggers, and Lightning components carry their own API version in their -meta.xml files.
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<status>Active</status>
</ApexClass>
The class's API version determines which platform APIs are available to its code, which annotations are valid, and how the platform interprets certain syntactic constructs. A class with apiVersion=55.0 cannot use a feature introduced in 60.0 even if the project's sourceApiVersion is 62.0.
A common refactor is to bulk-update all meta XML files to a current version:
find force-app -name '*.cls-meta.xml' -exec \
sed -i.bak 's|<apiVersion>5[0-9].0</apiVersion>|<apiVersion>62.0</apiVersion>|' {} +
Use the sed snippet selectively. Some legacy classes need older versions to maintain specific behavioral guarantees.
Edge case: managed packages and API versions
Managed packages ship at their publisher's chosen API version. When you install a package, the package's classes carry that version, not your org's project default. Upgrading the package may bump the version; subscribers cannot directly override it.
If your code depends on a package class and the package upgrades to use a newer API endpoint that your org's default version does not support, your callouts fail. The fix is usually to bump your own code's API version to match the package, or to add a thin wrapper that calls the package at the package's version.
Edge case: legacy SOAP API endpoints
The Tooling API, Metadata API, Bulk API, and REST API each have their own version-numbered endpoints. The CLI assembles URLs using the requested version. A mismatch between your project's version and the org's installed API versions can occur if the org is on a different release window (sandboxes lag production by one major release until the org upgrade).
Check the org's API version explicitly:
sf org display --target-org staging --json | jq '.result.apiVersion'
If the org reports 60.0 and your project says 62.0, certain endpoints in your project's chosen version may not exist yet in the staging org. Match your sourceApiVersion to the lowest org version you deploy to.
Edge case: sf command vs legacy sfdx
The sf CLI replaced sfdx in 2023. Both binaries can coexist. They use the same configuration files but expose different flag names (--api-version vs --apiversion). Scripts written for the older sfdx may break on a fresh installation that only has sf.
If your CI invokes sfdx commands, install the compatibility shim or rewrite the script to use sf commands. The flag names are the most common source of subtle errors.
Test patterns
A CI step that validates the API version alignment before deploying:
PROJECT_VERSION=$(jq -r '.sourceApiVersion' sfdx-project.json)
ORG_VERSION=$(sf org display --target-org staging --json | jq -r '.result.apiVersion')
if [ "$PROJECT_VERSION" != "$ORG_VERSION" ]; then
echo "Project version ($PROJECT_VERSION) does not match org version ($ORG_VERSION)"
exit 1
fi
The check runs before the actual deploy. A mismatch fails the pipeline early with a clear message instead of a cryptic resource-not-allowed error.
For functional tests, run the CLI commands locally against a scratch org with the target API version. The scratch-org definition can specify the version:
{
"orgName": "Test Org",
"edition": "Developer",
"release": "preview"
}
release: preview pulls the next release's version. Combined with the project's sourceApiVersion, you can test forward-looking changes.
Diagnosing in production
When the error fires:
- Run
sf --versionto identify the CLI version. - Inspect
sfdx-project.jsonforsourceApiVersion. - Inspect any explicit
--api-versionflags on the failing command. - Run
sf org display --jsonto identify the org's version. - Locate the documentation for the failing endpoint to find when it was added or deprecated.
- Choose: bump the project, pin the CLI, or pass an explicit flag.
The investigation is methodical. The version resolution order is fixed, so identifying the layer that produced the wrong version is straightforward once you know to look.
Anti-pattern: relying on CLI defaults silently
A pipeline that does not pin the CLI version inherits whatever the runner installs. CI runners update their package indexes regularly, so the CLI version drifts without notice. A pipeline that worked yesterday can fail today because the CLI's default API version changed.
Pin the CLI in CI. Document the version. Bump deliberately.
Defensive habits
Bump the project's API version with each new Salesforce release. The platform releases three times a year; bumping in lockstep avoids the silent-deprecation problem.
Run sf project deploy validate in CI on every PR. The validation catches version-related deploy issues at PR time.
Document the API version in the project README. Engineers joining the team know which version to expect.
Watch the Salesforce release notes for API-deprecation announcements. Endpoints are marked deprecated at least one release before removal, giving you a window to migrate.
Use scratch orgs for testing forward-looking changes. The release: preview setting on a scratch-org definition pulls the next release; deploy your code there to catch deprecations early.
Quick recovery checklist
- Identify the API version the CLI used in the failing call.
- Identify which layer produced it (flag, project, config, default).
- Bump or pin to align with the endpoint's availability.
- Validate the deploy in a sandbox.
- Update CI to lock the alignment.
The CLI-version mismatch is operational, not architectural. The fix is short. The work that pays off is the process discipline that prevents drift.
Further reading from Salesforce
- Salesforce CLI Setup Guide
- API Developer Guide: Version-Specific Behavior
- Salesforce CLI Command Reference
- Architect: DevOps with Salesforce CLI
- Trailhead: Salesforce CLI
Related dictionary terms
Share this fix
Related Salesforce errors
ENOENT: no such file or directory
CLI · sfThe Salesforce CLI couldn't find a file or directory you referenced. Almost always a working-directory mismatch — the CLI is running in `/so…
ERROR running force:auth:web:login: Invalid login URL
CLI · sfThe Salesforce CLI couldn't authenticate against the URL you gave it. Either the URL is wrong (typo, missing https, hitting a non-Salesforce…
My Domain is required for this org / Lightning components require My Domain to be deployed
CLI · sfMany Salesforce features (Lightning components, Connected Apps, single sign-on, Communities) require My Domain to be set up in the org. New …
Source push not allowed in this org. Source tracking is not enabled.
CLI · sfYou ran `sf project deploy start` (or `sfdx force:source:push`) against an org that doesn't have source tracking — production, a fully-copie…
@wire(getRecord, ...) requires the fields property
Lightning · LWCYou used `getRecord` from `lightning/uiRecordApi` without specifying which fields to fetch. LDS doesn't auto-fetch all fields like an old-sc…