Hidden Assumptions in strapi

13 assumptions this code never checks · 4 critical · spanning Domain, Shape, Contract, Ordering, Temporal, Resource, Environment, Scale

Every codebase relies on things it never checks. Most of them are routine. CodeSea looked at strapi/strapi and picked out the few most likely to cause trouble. The full list is just below.

Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".

Worth your attention first

If production deployment uses localhost (like Docker containers or local staging), cloud plugin gets incorrectly enabled. If development uses custom domains, plugin gets incorrectly disabled.

Worth your attention first

Invalid email addresses get passed directly to Mailgun API, causing API errors or silent delivery failures instead of early validation errors

Worth your attention first

If plopfile exports different structure (named exports, class, object), generator execution fails with cryptic 'not a function' errors

Show everything (10 more)
Ordering

Actions in ctx.state.actions array can be executed sequentially without dependencies - each action.build(ctx) call is independent

If this fails: If actions have dependencies (e.g., content type must exist before fixtures), build() executes them in registration order which may cause 'model not found' or constraint violation errors

packages/utils/api-tests/builder/index.js:build
Temporal

The nodeSES client callback (err) => {} is always called exactly once per sendEmail call

If this fails: If AWS SES client hangs, times out, or calls callback multiple times, Promise never resolves/rejects or resolves/rejects multiple times causing memory leaks or duplicate processing

packages/providers/email-amazon-ses/src/index.ts:send
Resource

Translation files exist at ./translations/${locale}.json for all locales in app.locales array, and dynamic imports won't exceed module loading limits

If this fails: Missing translation files fail silently (catch returns empty data), but excessive locales could hit Node.js module cache limits or cause memory pressure during parallel imports

packages/plugins/cloud/admin/src/index.ts:registerTrads
Environment

Current working directory (process.cwd()) is writable and the join(dir, 'src') path structure exists or can be created by the template system

If this fails: If running in read-only filesystem or restricted permissions, template generation fails with EACCES errors. If 'src' directory structure doesn't match template expectations, files get created in unexpected locations

packages/generators/generators/src/index.ts:generate
Shape

strapi.getModel(modelsUtils.toContentTypeUID(modelName)) always returns a valid model object that strapi.contentAPI.sanitize.output can process

If this fails: If modelName doesn't correspond to registered content type or toContentTypeUID transforms incorrectly, getModel returns undefined causing sanitize.output to throw TypeError

packages/utils/api-tests/builder/index.js:sanitizedFixturesFor
Domain

The 'h:Reply-To' header format is the correct Mailgun API syntax and replyTo email addresses are valid RFC 5322 format

If this fails: If Mailgun changes header syntax or receives malformed reply-to addresses, emails send without reply-to functionality or get rejected by recipient servers

packages/providers/email-mailgun/src/index.ts:init
Scale

Default regex pattern '^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$' covers all valid color formats the application needs - assumes only hex colors

If this fails: Users cannot input valid CSS colors like 'rgb(255,0,0)', 'hsl(0,100%,50%)', or named colors like 'red', causing validation errors for legitimate color values

packages/plugins/color-picker/admin/src/index.ts:register
Contract

StrapiAppPlugin objects have register() and registerTrads() functions that accept 'app' parameter with specific methods like addMenuLink, registerPlugin

If this fails: If plugin doesn't implement expected interface or app object lacks required methods, admin panel initialization fails with 'undefined is not a function' errors during plugin loading

packages/core/admin/admin/src/index.ts:StrapiAppPlugin
Environment

Environment variable APP_KEYS contains properly formatted array strings that can be parsed by env.array() - assumes consistent deployment configuration

If this fails: If APP_KEYS is malformed or missing in production, falls back to development keys 'toBeModified1', 'toBeModified2' which compromises security of signed cookies and sessions

examples/complex/config/server.ts:serverConfig
Temporal

Test data cleanup can be safely performed after tests complete - assumes no concurrent test execution or shared database state

If this fails: If tests run in parallel or share database instances, cleanup may delete data from running tests causing intermittent test failures or data corruption

packages/utils/api-tests/builder/index.js:cleanup

See the full structural analysis of strapi: the pipeline, data models, and system behavior that put these assumptions in context.

Full analysis of strapi/strapi →

Compare strapi

Frequently Asked Questions

What does strapi assume that could break in production?

The one most likely to cause trouble: Development environment is determined solely by checking if backendURL contains 'localhost' - assumes localhost always means development and production never uses localhost If this fails, If production deployment uses localhost (like Docker containers or local staging), cloud plugin gets incorrectly enabled. If development uses custom domains, plugin gets incorrectly disabled.

How many hidden assumptions does strapi have?

CodeSea found 13 assumptions strapi relies on but never validates, 4 of them critical, spanning Domain, Shape, Contract, Ordering, Temporal, Resource, Environment, Scale. Most are routine — the analysis flags the two or three most likely to actually bite.

What is a hidden assumption?

Something the code depends on but never checks: a data shape, an ordering, an environment condition, a scale limit, or a contract with another service. It holds until the world it runs in changes, then fails silently.