You have exceeded the maximum number of scheduled Apex jobs (100)
Salesforce caps each org at 100 scheduled Apex jobs in the queue at a time. Once you hit 100, scheduling a new job fails. Audit `CronTrigger` for stale jobs; abort or consolidate before scheduling more.
Also seen asmaximum number of scheduled Apex jobs·100 scheduled jobs·schedule limit·ScheduleException
The 100-job cap counts every Apex class scheduled with System.schedule(...). If your org has been running for years, old jobs accumulate — schedules created during pilots, testing, abandoned features.
Audit existing scheduled jobs
SELECT Id, CronJobDetail.Name, NextFireTime, State
FROM CronTrigger
WHERE CronJobDetail.JobType = '7' -- Scheduled Apex
ORDER BY CronJobDetail.Name
(JobType = '7' is Scheduled Apex; other JobTypes are Batch, Future, etc.)
The result shows your job count. Over 90 = warning territory.
Abort stale jobs
List<CronTrigger> jobs = [
SELECT Id, CronJobDetail.Name FROM CronTrigger
WHERE CronJobDetail.JobType = '7'
];
for (CronTrigger ct : jobs) {
if (ct.CronJobDetail.Name.startsWith('Old_')) {
System.abortJob(ct.Id);
}
}
System.abortJob removes a job immediately. Other jobs are unaffected. Once aborted, the slot frees and you can schedule a new one.
Fix: consolidate schedules
If you have 50 hourly jobs, consider one master scheduler that calls all of them:
public class MasterScheduler implements Schedulable {
public void execute(SchedulableContext ctx) {
Database.executeBatch(new JobA());
System.enqueueJob(new JobB());
new JobC().run();
}
}
One job in the queue, multiple jobs execute. Cleaner, easier to monitor, doesn't bump against the 100 cap.
Fix: use Queueable chains for one-time deferred work
System.schedule(...) is for recurring schedules. For "run X in 5 minutes" you don't need a schedule:
System.scheduleBatch(new MyBatch(), 'OneTimeRun_' + System.now().getTime(), 5);
Or use enqueueJob with a delay flag. These don't accumulate persistent CronTrigger rows.
A subtle source: scheduled tests in test classes
@isTest static void testScheduling() {
System.schedule('Test_' + DateTime.now().getTime(), '0 0 1 * * ?', new MyJob());
Test.startTest();
Test.stopTest();
}
Tests sometimes fire System.schedule and forget to abort in the teardown. Each test run accumulates one more CronTrigger row. After enough test runs, you blow the cap.
Fix: always wrap in Test.startTest() / Test.stopTest(). The platform automatically aborts test-context schedules when the test ends.
When the org has too many job runs in flight
Different cap, similar feel. The org allows 5 concurrently running scheduled jobs. If five are simultaneously executing, the next scheduled fire-time is queued. Long-running jobs blocking new ones can manifest as "schedule limit exceeded" though that's misnamed — it's actually the in-flight cap.
Keep individual scheduled jobs short; offload heavy work to Batch Apex called from the schedulable.
