A Cloudflare Worker deployment once stopped with this message:
CPU limits are not supported for the Free plan.
Switch to a paid plan ... to set CPU limits.
[code: 100328]
The natural reaction is:
But the Free plan already has a CPU limit. Why is Cloudflare rejecting a CPU limit?
Because two different concepts are being mixed together.
The Workers Free plan has a platform CPU allowance. Configuring limits.cpu_ms is a separate feature.
If Wrangler sends an explicit custom CPU limit for a plan that does not support configurable CPU limits, Cloudflare can reject the deployment before your Worker ever runs.
That is what error 100328 is about.
First: this is a deployment error, not a runtime timeout
Cloudflare currently documents the Workers Free CPU allowance as 10 ms of CPU time per HTTP request.
Workers Paid supports a much larger configurable ceiling—up to five minutes per HTTP request, with a 30-second default on the paid plan.
But the message CPU limits are not supported for the Free plan appears while publishing configuration.
Your code may not have executed at all.
That makes this different from:
Error 1102
Worker exceeded resource limits
Cloudflare documents Error 1102 / exceededCpu as the runtime failure when an invocation actually uses too much CPU.
So start by classifying the incident:
| Symptom | Meaning |
|---|---|
100328 CPU limits are not supported for the Free plan |
Deployment/configuration is trying to set an unsupported custom CPU limit |
1102 Worker exceeded resource limits |
A deployed Worker invocation exceeded runtime resource limits |
The fix paths are different.
Check the effective Wrangler configuration
Wrangler supports a limits section with fields such as cpu_ms.
For example:
[limits]
cpu_ms = 1000
or JSON/JSONC:
{
"limits": {
"cpu_ms": 1000
}
}
If the account is on the Free plan, an explicit CPU-limit configuration can trigger the deployment rejection.
The first fix is not to rewrite your application.
Find where that configuration is coming from.
The setting may not be in the top-level config
This is where troubleshooting often takes longer than expected.
You inspect wrangler.toml, do not see a top-level cpu_ms, and assume Cloudflare is wrong.
Check environment-specific configuration too.
For example:
[env.production.limits]
cpu_ms = 1000
or:
[env.development.limits]
cpu_ms = 10
Then consider how you deploy:
wrangler deploy --env production
The effective environment may contain configuration the base section does not.
Also check:
wrangler.json/wrangler.jsonc;- generated framework config;
- Infrastructure-as-Code output;
- CI-generated Wrangler files;
- deployment scripts that select another config with
--config; - stale copied config in a deployment directory.
Debug the configuration Wrangler actually sends, not only the file you remember editing.
Why cpu_ms = 10 can still be rejected
This is the confusing case.
You might reason:
Free Workers have 10 ms of CPU time. I set
cpu_ms = 10, so I am not asking for anything extra.
But setting the value is still asking Cloudflare to apply the custom CPU-limit configuration feature.
The platform’s built-in Free allowance is automatic.
You do not need to restate it in limits.cpu_ms.
So if your goal is simply:
Keep this Worker on the Free plan with normal Free-plan behaviour,
remove the explicit CPU-limit configuration from the effective deployment config.
When you should upgrade instead of deleting the setting
Do not remove a limit mechanically if the configuration existed for a real reason.
Maybe the application genuinely needs more CPU for:
- heavy server-side rendering;
- large JSON transformation;
- cryptographic work;
- compression/parsing;
- image/data processing;
- complex business computation.
Cloudflare’s current Workers limits documentation says heavier workloads such as authentication, SSR and large-payload processing can use more CPU than very lightweight Workers.
If your application legitimately needs a configurable CPU budget beyond the Free-plan constraints, the right answer may be the paid Workers plan.
Then set the custom limit intentionally and monitor the real CPU usage.
The decision is:
unsupported config accidentally present? Remove it.
versus
workload actually needs configurable CPU? Use the plan designed for it.
Do not “fix” deployment and ignore a real CPU problem
Suppose you remove cpu_ms and deployment succeeds.
That does not prove the application fits within Free-plan runtime CPU behaviour.
Run the actual routes and inspect Worker logs/metrics.
If production now returns runtime CPU errors, you have uncovered the second problem rather than solved everything.
Cloudflare recommends using Worker logs and CPU profiling to identify CPU-intensive code.
A clean troubleshooting sequence is:
- remove unsupported deployment configuration;
- deploy successfully;
- exercise representative production routes;
- inspect CPU time/outcomes;
- optimize or change plan based on measured workload.
Do not guess from bundle size or wall-clock latency alone.
CPU time is not wall time
Cloudflare distinguishes CPU time from elapsed/wall time.
Waiting for I/O such as:
fetch();- KV reads;
- database requests;
is not counted the same way as actively executing JavaScript on the CPU.
A Worker can take hundreds of milliseconds end-to-end while using only a few milliseconds of CPU.
Conversely, a tight computation can exceed CPU limits very quickly even without network requests.
This matters because changing D1 queries or API latency will not automatically fix a CPU-bound algorithm.
Measure the correct resource.
Environment inheritance has historically caused confusion
There has also been a Workers SDK issue around Wrangler environment limits configuration where removing a cpu_ms value from an environment produced a configuration/inheritance problem in a particular Wrangler version.
That historical issue is another reason I would check your current Wrangler version and current effective config rather than copying an old workaround blindly.
If removing cpu_ms produces a new Wrangler validation error, update/check the current Workers SDK behaviour before concluding the Free plan requires you to set it.
The current Cloudflare documentation is the source of truth for supported configuration.
CI can deploy a different configuration than your laptop
This is especially common in production pipelines.
Locally you run:
wrangler deploy
CI runs:
wrangler deploy --env production --config wrangler.production.toml
The local file is clean.
The production file contains:
[limits]
cpu_ms = 30000
Now the error only appears in CI.
Before editing application code, log or inspect:
- Wrangler version;
- selected environment;
- selected config path;
- account/Worker plan;
- effective
limitssection.
Do not print secrets while dumping configuration.
Framework-generated Wrangler files deserve inspection
Modern Cloudflare frameworks and deployment adapters can generate Worker configuration during build.
Your source repository may not contain the exact final file uploaded to Cloudflare.
If 100328 appears unexpectedly:
- inspect build output;
- inspect generated Wrangler config;
- check adapter defaults;
- compare the successful previous deployment artifact/config with the failing one.
The question is:
Who added
limits.cpu_msto the effective deployment?
That is usually much faster than assuming the account plan changed mysteriously.
A safe fix checklist
When Wrangler reports:
CPU limits are not supported for the Free plan
[code: 100328]
I use this sequence:
- Confirm the Worker/account is actually on the Free plan.
- Search all Wrangler config files for
cpu_ms. - Check environment-specific
[env.*.limits]sections. - Check the exact
--envand--configused by CI. - Inspect generated framework/IaC config if applicable.
- If staying Free, remove the explicit CPU-limit setting from the effective config.
- If the workload needs configurable CPU, move to an appropriate paid plan and set the limit deliberately.
- Deploy again and distinguish any new runtime Error 1102 from the original deployment error.
- Measure real CPU usage on representative SSR/API routes.
- Keep plan-specific limits in deployment documentation so they are not reintroduced later.
Why this exact-error article matters
The Cloudflare message is technically accurate but easy to misread.
A developer sees:
Free plan: 10 ms CPU
and naturally assumes:
cpu_ms = 10
should be valid.
But the fixed Free-plan allowance and the configurable limit control are different product behaviours.
Once you separate those concepts, error 100328 becomes straightforward:
your deployment is asking Cloudflare to configure a CPU limit on a plan that does not support that configuration.
Fix the effective configuration—or deliberately choose the plan that supports the requirement.
If a Cloudflare deployment suddenly breaks in CI and the error seems unrelated to the code you changed, contact me or see my MVP development service. I debug production boundaries like this from build configuration through runtime behaviour rather than patching application code that was never the failing layer.



