Troubleshooting

PNG returns 500 with "No CJK font loaded from KV"

Cause: font:arial-unicode-cn-gb2312 is missing or zero-byte in the SHORT_LINKS KV namespace. Without it, loadFonts throws (src/render.ts L92).

Fix: re-upload the CJK font (see Configuration page). SVG endpoints will still work — only PNG is affected.

Short link returns 404 short_link_not_found

The 30-day TTL expired or the KV record was deleted. resolveShortLink (src/index.ts L2372) calls env.SHORT_LINKS.get("short:" + token) — if null, returns 404.

For permanent references, use the long ?d= URL form. buildShortUrl (L2306) falls back to long URL when the encoded payload is <= 3600 chars.

SVG rendered but no CJK characters appear

SVG output uses regular &lt;text&gt; elements. Browsers may fall back to a default font if the device doesn't have CJK support. The PNG path uses pathifyCjkText (src/render.ts L139) which converts CJK glyphs to SVG paths — PNG is reliable across viewers.

expr-eval parse error on math expression

Parser.parse(expr) throws Parse error on.... The expression is truncated to 400 chars (MAX_EXPR_LENGTH) before parsing. Supported: +, -, *, /, ^ (power), sin/cos/tan/asin/acos/atan, log/ln/exp/sqrt/abs, min/max, PI/e constants, if/then/else, parentheses.

Force analysis diagram looks crowded

sanitizeForceAnalysisPayload (src/index.ts L848) auto-simplifies dense layouts. If you have 5+ forces on a single body, components/axes/angle labels/resultant may be hidden with a warning field. Pass show_components: true, show_axes: true, show_resultant: true, show_angle_labels: true explicitly to override.

Circuit template produces wrong layout

10 templates, each with different parameters. The default series template expects no extra params. parallel, switch_lamp, source_resistor, etc. each take specific resistor_label/source_label/switch_label args. See src/index.ts L529-545 for the schema.

Tool call returns unknown_tool:{name}

The name didn't resolve via lookupCompat (legacy) or resolveCanonicalToLegacy (canonical). Check spelling. Use one of the 24 names from the tools/list response or from the Tools Reference page.

PNG output is huge (multi-MB)

Default canvas is 1200x720. For subplot grids, outerWidth scales with row*col. If you have a 3x3 grid with large series, expect 5-10 MB PNGs. Pass a smaller series (points) or use SVG (render.format = "svg") which compresses better.

Deploy fails with "binding SHORT_LINKS not found"

The KV namespace ID in wrangler.toml (L12) doesn't match your account. Either update the id field or run wrangler kv:namespace create SHORT_LINKS and replace.

Force analysis drift detected

npm run check:force-drift computes a hash of the local-generated SVG and compares to the deployed worker. If they differ, the rendered output has changed — usually because sanitizeForceAnalysisPayload auto-simplification rules changed, or a renderForceAnalysisSvg in src/extras.ts was modified. Read both diffs before re-deploying.

Deploy preflight flags an issue

npm run check:deploy-preflight runs several sanity checks (type-check, font presence in KV, KV namespace accessibility). If it fails, read the script's stderr — it tells you which check failed.

wrangler: treat .ttf files as data (separate asset) and fall through to the next matching rule. This is what lets the fonts live in KV instead of being inlined into the worker bundle.

Constants (from src/constants.ts)

ConstantValueUsed for
SERVER_NAME"plot-mcp-worker"health/init response
SERVER_VERSION"0.4.14"health/init response (differs from package.json)
SHORT_LINK_PATH_PREFIX"/s/"Short URL path prefix
SHORT_LINK_TOKEN_LENGTH8Token length
SHORT_LINK_TTL_SECONDS2592000 (30 days)KV TTL for short link records
MIN_POINTS / MAX_POINTS10 / 20000Series point count clamp
DEFAULT_POINTS1000When caller doesn't specify
MAX_EXPR_LENGTH400Truncate math expressions
MAX_TITLE_LENGTH120Truncate titles
MAX_LABEL_LENGTH80Truncate labels
MAX_SERIES12Max series per plot
MAX_FORCE_ITEMS16Max forces per body
MAX_FORCE_BODIES8Max bodies in one scene
MAX_CIRCUIT_COMPONENTS24Max components per circuit
MAX_3D_SURFACES6Max surfaces in 3D scene
DEFAULT_WIDTH / DEFAULT_HEIGHT1200 / 720SVG/PNG canvas size
DEFAULT_FONT_FAMILY"ArialUnicodeCN"Used for resvg font lookup
DEFAULT_PALETTE8 colors (blue/red/green/amber/purple/cyan/orange/pink)Series auto-color when caller omits color

TypeScript config (tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "Bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "types": ["@cloudflare/workers-types"]
  },
  "include": ["src/**/*.ts"]
}

ES2022 + strict mode. skipLibCheck skips checking @cloudflare/workers-types. Wrangler's Bundler resolution mode means you don't need to declare explicit import paths for the npm dependencies.

wrangler: treat .ttf files as data (separate asset) and fall through to the next matching rule. This is what lets the fonts live in KV instead of being inlined into the worker bundle.

Constants (from src/constants.ts)

ConstantValueUsed for
SERVER_NAME"plot-mcp-worker"health/init response
SERVER_VERSION"0.4.14"health/init response (differs from package.json)
SHORT_LINK_PATH_PREFIX"/s/"Short URL path prefix
SHORT_LINK_TOKEN_LENGTH8Token length
SHORT_LINK_TTL_SECONDS2592000 (30 days)KV TTL for short link records
MIN_POINTS / MAX_POINTS10 / 20000Series point count clamp
DEFAULT_POINTS1000When caller doesn't specify
MAX_EXPR_LENGTH400Truncate math expressions
MAX_TITLE_LENGTH120Truncate titles
MAX_LABEL_LENGTH80Truncate labels
MAX_SERIES12Max series per plot
MAX_FORCE_ITEMS16Max forces per body
MAX_FORCE_BODIES8Max bodies in one scene
MAX_CIRCUIT_COMPONENTS24Max components per circuit
MAX_3D_SURFACES6Max surfaces in 3D scene
DEFAULT_WIDTH / DEFAULT_HEIGHT1200 / 720SVG/PNG canvas size
DEFAULT_FONT_FAMILY"ArialUnicodeCN"Used for resvg font lookup
DEFAULT_PALETTE8 colors (blue/red/green/amber/purple/cyan/orange/pink)Series auto-color when caller omits color

TypeScript config (tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "Bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "types": ["@cloudflare/workers-types"]
  },
  "include": ["src/**/*.ts"]
}

ES2022 + strict mode. skipLibCheck skips checking @cloudflare/workers-types. Wrangler's Bundler resolution mode means you don't need to declare explicit import paths for the npm dependencies.

wrangler: treat .ttf files as data (separate asset) and fall through to the next matching rule. This is what lets the fonts live in KV instead of being inlined into the worker bundle.

Constants (from src/constants.ts)

ConstantValueUsed for
SERVER_NAME"plot-mcp-worker"health/init response
SERVER_VERSION"0.4.14"health/init response (differs from package.json)
SHORT_LINK_PATH_PREFIX"/s/"Short URL path prefix
SHORT_LINK_TOKEN_LENGTH8Token length
SHORT_LINK_TTL_SECONDS2592000 (30 days)KV TTL for short link records
MIN_POINTS / MAX_POINTS10 / 20000Series point count clamp
DEFAULT_POINTS1000When caller doesn't specify
MAX_EXPR_LENGTH400Truncate math expressions
MAX_TITLE_LENGTH120Truncate titles
MAX_LABEL_LENGTH80Truncate labels
MAX_SERIES12Max series per plot
MAX_FORCE_ITEMS16Max forces per body
MAX_FORCE_BODIES8Max bodies in one scene
MAX_CIRCUIT_COMPONENTS24Max components per circuit
MAX_3D_SURFACES6Max surfaces in 3D scene
DEFAULT_WIDTH / DEFAULT_HEIGHT1200 / 720SVG/PNG canvas size
DEFAULT_FONT_FAMILY"ArialUnicodeCN"Used for resvg font lookup
DEFAULT_PALETTE8 colors (blue/red/green/amber/purple/cyan/orange/pink)Series auto-color when caller omits color

TypeScript config (tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "Bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "types": ["@cloudflare/workers-types"]
  },
  "include": ["src/**/*.ts"]
}

ES2022 + strict mode. skipLibCheck skips checking @cloudflare/workers-types. Wrangler's Bundler resolution mode means you don't need to declare explicit import paths for the npm dependencies.