# validate_diagram

> Page: https://docs.plotwork.dev/mcp/tools/validate-diagram. Index of every page: https://docs.plotwork.dev/llms.txt

Check diagram source without drawing it: every error in one pass, each with line, column, and a fix hint, plus quality warnings. It is a single tool of the MCP server and the HTTP API, with the title "Validate diagram".

## TL;DR

| Question | Answer |
|---|---|
| What is it? | A single tool: it does one thing. |
| What does it do? | Check diagram source without drawing it: every error in one pass, each with line, column, and a fix hint, plus quality warnings. |
| How do I call it over HTTP? | [`POST /v1/diagrams/validate`](https://docs.plotwork.dev/api/post-v1-diagrams-validate.md) |
| Does it change anything? | No. It is read-only and idempotent, and it talks to nothing outside itself. It saves no file and returns its answer as data. |
| Which bounds apply? | None beyond the limits of each argument, which are in the schema below. |
| Where do I read its schema as data? | An MCP client gets the name, description, and JSON Schema of every tool from `tools/list`. |

## What it does

Check diagram source without drawing it: every error in one pass, each with line, column, and a fix hint, plus quality warnings. An icon a label names for certain is drawn already; W204 gives the exact icon=provider:name for a node whose label names a product it does not draw (a brand whose name is also an everyday word, or every match under icons=off), W205 the type= for a group whose name matches a group type, and W206 flags an overlay framing a node that is not its member. These suggestions are not applied for you: add one, or icon=none to keep a node plain, and validate again. Prefer draw_diagram, which checks, describes, and draws in one call.

## Arguments

| Field | Type | Required | Description |
|---|---|---|---|
| `source` | `string` | yes | Diagram source; the first line is the header, such as flow "Title" (draw_diagram lists every kind). at least 1 character; at most 50000 characters. |
| `settings` | `object` | no | The repo's plotwork.config.json, if any. Schema: https://docs.plotwork.dev/schemas/plotwork.config.json. |

## Result

| Field | Type | Required | Description |
|---|---|---|---|
| `valid` | `boolean` | yes | True when there are no errors; warnings do not make a diagram invalid. |
| `kind` | `string \| null` | yes | The diagram kind, or null when the header could not be read. |
| `errors` | `Diagnostic[]` | yes | Every error found in one pass, so they can be fixed together. |
| `errors[].code` | `"E100" \| "E101" \| "E110" \| "E111" \| "E120" \| "E121" \| "E122" \| "E123" \| "E124" \| "E125" \| "E130" \| "E131" \| "E132" \| "E133" \| "E134" \| "E135" \| "E136" \| "E137" \| "E138" \| "E139" \| "E140" \| "W200" \| "W201" \| "W202" \| "W203" \| "W204" \| "W205" \| "W206" \| "W207" \| "W500" \| "M100" \| "M101" \| "M102" \| "M103" \| "M104" \| "M110" \| "M200" \| "M201" \| "M202" \| "M203" \| "M204" \| "M205" \| "M206" \| "M207" \| "M208" \| "M209" \| "M210" \| "M211" \| "M212" \| "M213" \| "M214" \| "M215" \| "M216" \| "M217" \| "M218" \| "E300" \| "E301" \| "E302" \| "E303" \| "E304" \| "W300" \| "W301" \| "W302" \| "W303" \| "M120" \| "M220" \| "M221" \| "M222" \| "E340" \| "E341" \| "E342" \| "E343" \| "E344" \| "E345" \| "W320" \| "W321" \| "W322" \| "W323" \| "M240" \| "M241" \| "M242" \| "E360" \| "E361" \| "E362" \| "E363" \| "E364" \| "E365" \| "E366" \| "E367" \| "W330" \| "W331" \| "W332" \| "W333" \| "W334" \| "M250" \| "M251" \| "E400" \| "E401" \| "E402" \| "E403" \| "W350" \| "W351" \| "W352" \| "W353" \| "M270" \| "M271" \| "E420" \| "E421" \| "E422" \| "E423" \| "E424" \| "W360" \| "W361" \| "W362" \| "W363" \| "W364" \| "M180" \| "M280" \| "M281" \| "M282" \| "E320" \| "E321" \| "E322" \| "E323" \| "E324" \| "E325" \| "E326" \| "E327" \| "E328" \| "E329" \| "E330" \| "W310" \| "W311" \| "W312" \| "W313" \| "W314" \| "M130" \| "M131" \| "M132" \| "M230" \| "M231" \| "M232" \| "M233" \| "M234" \| "M235" \| "M236" \| "M237" \| "M238" \| "E380" \| "E381" \| "E382" \| "E383" \| "W340" \| "W341" \| "W342" \| "W343" \| "M260" \| "I100" \| "I101" \| "I102" \| "I103" \| "I104" \| "I105" \| "I200" \| "I201" \| "I202" \| "I203" \| "I204" \| "I206" \| "R100" \| "R101" \| "R200" \| "R201" \| "R202" \| "R203" \| "R204" \| "R205" \| "R206" \| "R207" \| "S100" \| "S200" \| "S101" \| "S102" \| "S103" \| "S104" \| "S201" \| "S202" \| "S203"` | yes | Stable code to branch on; E-codes are errors, W-codes are warnings. |
| `errors[].severity` | `"error" \| "warning"` | yes | Errors stop rendering; warnings never do. |
| `errors[].message` | `string` | yes | What is wrong, in one sentence. |
| `errors[].line` | `integer` | yes | 1-based line in the submitted source. minimum 1. |
| `errors[].column` | `integer` | yes | 1-based column in that line. minimum 1. |
| `errors[].length` | `integer` | yes | Number of characters the problem covers. minimum 1. |
| `errors[].hint` | `string \| null` | yes | A concrete suggestion for fixing it, or null. |
| `warnings` | `Diagnostic[]` | yes | Quality warnings for a valid diagram, such as too dense or too wide. |
| `warnings[].code` | `"E100" \| "E101" \| "E110" \| "E111" \| "E120" \| "E121" \| "E122" \| "E123" \| "E124" \| "E125" \| "E130" \| "E131" \| "E132" \| "E133" \| "E134" \| "E135" \| "E136" \| "E137" \| "E138" \| "E139" \| "E140" \| "W200" \| "W201" \| "W202" \| "W203" \| "W204" \| "W205" \| "W206" \| "W207" \| "W500" \| "M100" \| "M101" \| "M102" \| "M103" \| "M104" \| "M110" \| "M200" \| "M201" \| "M202" \| "M203" \| "M204" \| "M205" \| "M206" \| "M207" \| "M208" \| "M209" \| "M210" \| "M211" \| "M212" \| "M213" \| "M214" \| "M215" \| "M216" \| "M217" \| "M218" \| "E300" \| "E301" \| "E302" \| "E303" \| "E304" \| "W300" \| "W301" \| "W302" \| "W303" \| "M120" \| "M220" \| "M221" \| "M222" \| "E340" \| "E341" \| "E342" \| "E343" \| "E344" \| "E345" \| "W320" \| "W321" \| "W322" \| "W323" \| "M240" \| "M241" \| "M242" \| "E360" \| "E361" \| "E362" \| "E363" \| "E364" \| "E365" \| "E366" \| "E367" \| "W330" \| "W331" \| "W332" \| "W333" \| "W334" \| "M250" \| "M251" \| "E400" \| "E401" \| "E402" \| "E403" \| "W350" \| "W351" \| "W352" \| "W353" \| "M270" \| "M271" \| "E420" \| "E421" \| "E422" \| "E423" \| "E424" \| "W360" \| "W361" \| "W362" \| "W363" \| "W364" \| "M180" \| "M280" \| "M281" \| "M282" \| "E320" \| "E321" \| "E322" \| "E323" \| "E324" \| "E325" \| "E326" \| "E327" \| "E328" \| "E329" \| "E330" \| "W310" \| "W311" \| "W312" \| "W313" \| "W314" \| "M130" \| "M131" \| "M132" \| "M230" \| "M231" \| "M232" \| "M233" \| "M234" \| "M235" \| "M236" \| "M237" \| "M238" \| "E380" \| "E381" \| "E382" \| "E383" \| "W340" \| "W341" \| "W342" \| "W343" \| "M260" \| "I100" \| "I101" \| "I102" \| "I103" \| "I104" \| "I105" \| "I200" \| "I201" \| "I202" \| "I203" \| "I204" \| "I206" \| "R100" \| "R101" \| "R200" \| "R201" \| "R202" \| "R203" \| "R204" \| "R205" \| "R206" \| "R207" \| "S100" \| "S200" \| "S101" \| "S102" \| "S103" \| "S104" \| "S201" \| "S202" \| "S203"` | yes | Stable code to branch on; E-codes are errors, W-codes are warnings. |
| `warnings[].severity` | `"error" \| "warning"` | yes | Errors stop rendering; warnings never do. |
| `warnings[].message` | `string` | yes | What is wrong, in one sentence. |
| `warnings[].line` | `integer` | yes | 1-based line in the submitted source. minimum 1. |
| `warnings[].column` | `integer` | yes | 1-based column in that line. minimum 1. |
| `warnings[].length` | `integer` | yes | Number of characters the problem covers. minimum 1. |
| `warnings[].hint` | `string \| null` | yes | A concrete suggestion for fixing it, or null. |
| `summary` | `string \| null` | yes | One-line description of the diagram, or null when invalid. |
| `size` | `Size \| null` | yes | Natural rendered size, or null when invalid. |
| `quality` | `Quality` | no | How clean the laid-out diagram looks, with up to three changes; absent when invalid. |
| `quality.score` | `integer` | yes | 0 to 100; 100 is a picture with nothing to fix. The same diagram always gets the same score. minimum 0; maximum 100. |
| `quality.grade` | `"clean" \| "fair" \| "cluttered"` | yes | clean is 85 or more, fair 60 or more, cluttered below. |
| `quality.measures` | `object` | yes | What the score is made from: crossings, lineOverBox, labelOverlaps, smallestTextPx (in an 880px column), aspectRatio, emptySpace (0 to 1), longestLine (px), detour (1 is straight), the counts of boxes, lines, labels, series, and slices, and any measure the kind adds. |
| `quality.hints` | `string[]` | yes | Up to three changes, the one worth most first, each naming the statement or option to edit. |
| `quality.line` | `string` | yes | The grade, the score, and the first hint in one line. |
| `notices` | `Note[]` | no | Information notes, such as an icon alias resolved to a real icon; absent when there is none. |
| `notices[].code` | `string` | yes | A stable code, such as I122 for an icon alias. |
| `notices[].severity` | `"info"` | yes | A note never stops a drawing and is not a warning. |
| `notices[].message` | `string` | yes |  |
| `notices[].line` | `integer` | yes | minimum 1. |
| `notices[].column` | `integer` | yes | minimum 1. |
| `notices[].length` | `integer` | yes | minimum 1. |
| `notices[].hint` | `string \| null` | yes | The text to write instead. |

## Behavior hints

| Hint | Value |
|---|---|
| `readOnlyHint` | true |
| `destructiveHint` | false |
| `idempotentHint` | true |
| `openWorldHint` | false |

## See also

| Doc | Why |
|---|---|
| [Tool reference](https://docs.plotwork.dev/mcp/tools.md) | Every tool, with the workflows first |
| [`POST /v1/diagrams/validate`](https://docs.plotwork.dev/api/post-v1-diagrams-validate.md) | The same operation over HTTP |
| [Language reference](https://docs.plotwork.dev/reference/language.md) | What the diagram source may contain |
| [Writing diagrams with an agent](https://docs.plotwork.dev/mcp/agent-loop.md) | The loop in practice |
