Hidden Assumptions in novel

12 assumptions this code never checks · 3 critical · spanning Domain, Shape, Contract, Environment, Ordering, Scale, Temporal

Every codebase relies on things it never checks. Most of them are routine. CodeSea looked at steven-tey/novel 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 the API route is missing, renamed, or returns different response format, image uploads fail silently or with cryptic errors - the promise resolves with the File object instead of URL, breaking image display

Worth your attention first

If MarkdownExtension isn't configured or storage structure changes, getPrevText() crashes with 'Cannot read property serialize of undefined', breaking AI completion context generation

Worth your attention first

Malformed File objects or files without proper MIME types bypass validation, potentially uploading non-images or oversized files that crash the upload endpoint

Show everything (9 more)
Environment

A DOM element with id 'slash-command' exists in the document when navigation keys are pressed during command mode

If this fails: If the command component unmounts or ID changes, keyboard navigation (ArrowUp, ArrowDown, Enter) fails silently - users can't navigate the command palette with keyboard

packages/headless/src/components/editor-command.tsx:onKeyDown
Ordering

Image preloading completes before the promise resolves, ensuring the image is ready for display when URL is returned

If this fails: If image.onload never fires (network issues, invalid URLs, CORS problems), the upload promise never resolves, leaving UI in loading state indefinitely

apps/web/components/tailwind/image-upload.ts:image.onload
Scale

20MB is a reasonable file size limit that won't exceed server memory or request size limits

If this fails: If the server has smaller limits (default Next.js is 1MB), uploads that pass client validation will fail server-side with unclear error messages

apps/web/components/tailwind/image-upload.ts:validateFn
Temporal

HTTP status codes have specific meanings: 200 = success with URL, 401 = missing blob token, anything else = unknown error

If this fails: If the API returns different status codes (403, 413, 500) or uses 200 for error states, the error handling logic misclassifies failures and shows wrong error messages

apps/web/components/tailwind/image-upload.ts:res.status
Contract

The tunnel instance from EditorCommandTunnelContext always has an Out component that can render without props

If this fails: If tunnel-rat library changes API or context is not properly initialized, rendering fails with 'Cannot read property Out of undefined'

packages/headless/src/components/editor-command.tsx:EditorCommandOut
Environment

The document object and addEventListener are available (browser environment) and keyboard events can be prevented and re-dispatched

If this fails: In server-side rendering or non-browser environments, document is undefined causing crashes during component mount

packages/headless/src/components/editor-command.tsx:navigationKeys
Domain

Strings containing dots but no spaces are likely URLs that can be prefixed with 'https://' to become valid URLs

If this fails: False positives like 'file.txt' or 'user.name' get converted to invalid HTTPS URLs, while valid URLs with spaces get rejected

packages/headless/src/utils/index.ts:getUrlFromString
Shape

Successful upload responses (status 200) always contain JSON with a 'url' string field

If this fails: If API returns different JSON structure or non-JSON response, destructuring fails with 'Cannot destructure property url of undefined'

apps/web/components/tailwind/image-upload.ts:res.json()
Contract

The ProseMirror document structure remains stable - editor.state.doc has a forEach method that calls callback with (node, pos) signature

If this fails: If Tiptap/ProseMirror changes document API, getPrevText fails with method not found errors

packages/headless/src/utils/index.ts:editor.state.doc.forEach

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

Full analysis of steven-tey/novel →

Frequently Asked Questions

What does novel assume that could break in production?

The one most likely to cause trouble: The /api/upload endpoint exists and accepts POST requests with file body and specific headers (content-type, x-vercel-filename), returning JSON with 'url' field on success If this fails, If the API route is missing, renamed, or returns different response format, image uploads fail silently or with cryptic errors - the promise resolves with the File object instead of URL, breaking image display

How many hidden assumptions does novel have?

CodeSea found 12 assumptions novel relies on but never validates, 3 of them critical, spanning Domain, Shape, Contract, Environment, Ordering, Scale, Temporal. 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.