Most Plate issues come from version skew, duplicate React/Plate runtimes, or
crossing the server/client import boundary. Start with package alignment, then
check runtime ownership, then inspect plugin resolution with DebugPlugin.
| Symptom | First check |
|---|---|
| Invalid hook call, null dispatcher, or React hook crashes. | Duplicate react / react-dom or mixed package-manager installs. |
| Plugins render as plain text or components do not attach. | Missing plugin, wrong /react versus base import, or wrong component map. |
| Server Component crashes on import. |
A Server Component imported platejs/react or platejs/<feature>/react. |
requires disabled plugin in the console. | An explicitly disabled plugin is required by an enabled plugin. |
Pass a plugin descriptor, not its name. | A dependency contains a string instead of a plugin descriptor. |
| Markdown, HTML, or static rendering misses nodes. | The static/base plugin kit does not include the serializer or node plugin. |
Use the focused guide when the issue belongs to one area:
| Area | Guide |
|---|---|
| Editor creation and options | Editor |
| Plugin configuration | Plugin |
| Plugin store state | Plugin Context |
| Debug logging | Debugging |
| Server Components | RSC |
| Static rendering | Static Rendering |
Plate editor features ship from one platejs package. Use the Plate CLI to
update it without managing a set of feature package versions.
For pnpm projects:
pnpm dlx @platejs/cli@latest deps platejs --latest --install --yespnpm dlx @platejs/cli@latest deps platejs --latest --install --yesThen inspect what actually resolved.
npm ls platejs react react-domnpm ls platejs react react-dompnpm why platejs
pnpm why react react-dompnpm why platejs
pnpm why react react-domIf the tree shows multiple Plate majors, align the Plate packages first. If it shows multiple React copies, fix the package that pulls the extra copy instead of papering over the tree with a random override.
Use React entrypoints only in client-side editor code.
| Runtime | Import from |
|---|---|
| Editable React editor | platejs/react, platejs/<feature>/react |
| Server Component static output | platejs/static, platejs, platejs/<feature> |
| Node script or route handler without React UI | platejs, platejs/<feature> |
Server Components and Node scripts should not import platejs/react or
platejs/<feature>/react. Use base plugins such as BaseHeadingPlugin from
platejs, not HeadingPlugin from platejs/react.
If a server route only needs serialization or transforms, use the Node path from Node.js. If it renders read-only React output, use Static Rendering.
When a node appears as plain text or a default div, check the component path.
import { HeadingPlugin } from 'platejs/react';
import { HeadingElement } from '@/components/editor/heading';
export const plugins = [HeadingPlugin.configure({ component: HeadingElement })];import { HeadingPlugin } from 'platejs/react';
import { HeadingElement } from '@/components/editor/heading';
export const plugins = [HeadingPlugin.configure({ component: HeadingElement })];For copied Plate UI kits, inspect the kit that owns the feature before adding manual component overrides. Feature kits usually wire plugins, components, shortcuts, and options together.
| Component surface | Guide |
|---|---|
| Copied registry components | Plate UI |
| Feature-owned kits | Feature Kits |
| Manual node components | Plugin Components |
Enable DebugPlugin when plugin state, dependencies, or runtime behavior do
not match what the editor receives.
import { DebugPlugin } from 'platejs';
export const plugins = [
DebugPlugin.configure({
initialState: {
logLevel: 'warn',
},
}),
];import { DebugPlugin } from 'platejs';
export const plugins = [
DebugPlugin.configure({
initialState: {
logLevel: 'warn',
},
}),
];Common debug errors:
| Message | Meaning |
|---|---|
requires disabled plugin | An enabled plugin requires a dependency that the app disabled. |
Circular plugin dependency | Plugin dependencies form a cycle. |
Use Plugin to check dependencies,
enabled, and override.* behavior.
When the dependency tree looks correct but the runtime still behaves like two React or Plate copies are loaded, reinstall from the existing lockfile.
rm -rf node_modules
npm installrm -rf node_modules
npm installrm -rf node_modules
pnpm installrm -rf node_modules
pnpm installDelete the lockfile only when you intentionally want a fresh dependency resolution. That is a package-management decision, not a Plate fix.
When you open an issue, include the smallest editor that reproduces the problem:
npm ls or pnpm why commands.useCreateEditor, createEditor, or
createStaticEditor.DebugPlugin or the browser console.Small reproductions beat screenshots. The package tree and plugin list usually tell the story.