Most Plate issues come from version skew, duplicate React/Plite 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/*/react. |
OPTION_UNDEFINED in the console. | Code reads or writes an option that is not declared in the plugin. |
PLUGIN_DEPENDENCY_MISSING in the console. | A plugin dependency name is not present in the editor plugin list. |
| 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 |
Keep platejs and every @platejs/* package on the same release family.
depset is the fastest way to update a project that already has several Plate
packages installed.
For pnpm projects:
pnpm dlx depset@latest @platejs --latest --install --yes
pnpm dlx depset@latest platejs --latest --install --yespnpm dlx depset@latest @platejs --latest --install --yes
pnpm dlx depset@latest platejs --latest --install --yesThen inspect what actually resolved.
npm ls platejs @platejs/core @platejs/plite @platejs/plite-dom @platejs/plite-react react react-domnpm ls platejs @platejs/core @platejs/plite @platejs/plite-dom @platejs/plite-react react react-dompnpm why platejs
pnpm why @platejs/core
pnpm why @platejs/plite
pnpm why @platejs/plite-dom @platejs/plite-react
pnpm why react react-dompnpm why platejs
pnpm why @platejs/core
pnpm why @platejs/plite
pnpm why @platejs/plite-dom @platejs/plite-react
pnpm why react react-domIf the tree shows multiple Plate majors, align the Plate packages first. If it shows multiple React or Plite 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/*/react |
| Server Component static output | platejs/static, platejs, @platejs/* |
| Node script or route handler without React UI | platejs, @platejs/* |
Server Components and Node scripts should not import platejs/react or
@platejs/*/react. Use base plugins such as BaseHeadingPlugin from
@platejs/basic-nodes, not HeadingPlugin from @platejs/basic-nodes/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/basic-nodes/react';
import { HeadingElement } from '@/components/editor/heading';
export const plugins = [HeadingPlugin.configure({ component: HeadingElement })];import { HeadingPlugin } from '@platejs/basic-nodes/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 |
|---|---|
PLUGIN_DEPENDENCY_MISSING | A plugin lists a dependency name that is not registered. |
Use Plugin to check dependencies,
enabled, and override.* behavior.
When the dependency tree looks correct but the runtime still behaves like two React or Plite 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.usePlateEditor, createPlateEditor,
createBaseEditor, or createStaticEditor.DebugPlugin or the browser console.Small reproductions beat screenshots. The package tree and plugin list usually tell the story.