Fishbone diagrams
A fishbone diagram, also called an Ishikawa or cause-and-effect diagram, sets out the causes of one problem. The problem is the head of the fish; the causes are grouped into categories, each a bone off the spine. Use it in an incident review, a root-cause analysis, or a quality meeting, when a team has a list of possible causes and wants to see them grouped and to mark the ones it has confirmed.
TL;DR
| Question | Answer |
|---|---|
| What is it for? | The causes of one problem, grouped by where they come from: people, process, machines, code, suppliers. |
| How do I start one? | Write fishbone "Title", an effect line for the problem, and a category block for each group with a cause line for each cause. |
| How deep can it go? | Three levels: category, cause, and sub-cause. A cause that ends with { holds sub-causes. |
| How do I mark a confirmed cause? | Add tone=red, or another tone, to the cause. It is drawn in that tone with a dot on its bone, and a key appears under the picture. |
| What does Mermaid convert? | ishikawa-beta and ishikawa. The first line is the effect; indentation gives the categories, causes, and sub-causes. See From Mermaid. |
| How big can it be? | At most 10 categories and 150 causes. Warnings start past 6 categories, past 8 causes on one bone, and at a category with no cause. |
| How is it drawn? | A spine with a tail, ending in the effect on a solid card. Categories alternate above and below the spine as slanted bones with a card at the end; causes sit on ticks off each bone. |
Ask your agent
Use Plotwork to draw a fishbone diagram of why checkout errors rose after our last release. Group the causes under People, Process, Infrastructure and Code, and mark the small connection pool as the confirmed root cause.Use Plotwork to draw a fishbone diagram of the causes in this incident review. Use the 6M categories, put sub-causes under the cause they explain, and give each category an icon.Example
An incident review: four categories, a sub-cause under the review that missed the change, and the confirmed root cause in red.
fishbone "Why checkout errors rose after 2.3" desc="The causes the incident review found for the rise in checkout errors, grouped by where they came from. The small connection pool is the confirmed root cause."effect "Checkout errors up 4x"category people "People" icon=lucide:users { cause "On-call runbook out of date" cause "New engineer on the first shift"}category process "Process" icon=lucide:workflow { cause "Canary skipped for a hotfix" cause "Review missed the timeout change" { cause "Diff over 2,000 lines" }}category infra "Infrastructure" icon=lucide:server { cause "Connection pool too small" tone=red cause "Database failover took 40 s"}category code "Code" icon=lucide:code { cause "Retry without backoff" cause "Timeout lowered to 2 s"}Effect: Checkout errors up 4x.
People: 2 causes.
- On-call runbook out of date
- New engineer on the first shift
Process: 3 causes.
- Canary skipped for a hotfix
- Review missed the timeout change
- Diff over 2,000 lines
Infrastructure: 2 causes.
- Connection pool too small (confirmed)
- Database failover took 40 s
Code: 2 causes.
- Retry without backoff
- Timeout lowered to 2 s
Confirmed: Connection pool too small (Infrastructure).
A manufacturing defect with the 6M categories
The six categories of the 6M set, in their usual order. The confirmed cause holds the two sub-causes the team traced it to.
fishbone "Cracked housings on line 3" desc="The 6M analysis of cracked plastic housings found at final inspection on line 3. Mould temperature drift is the confirmed cause."effect "Housings crack at inspection"category people "People" icon=lucide:users { cause "Night shift skips the warm-up check" cause "Operators trained on the old press"}category method "Method" icon=lucide:workflow { cause "Cycle time cut by 8 percent" cause "Cooling step shortened"}category machine "Machine" icon=lucide:cog { cause "Mould temperature drifts" tone=red { cause "Heater band worn" cause "Thermocouple out of calibration" } cause "Ejector pins misaligned"}category material "Material" icon=lucide:package { cause "Resin batch moisture high" cause "New supplier for colourant"}category measurement "Measurement" icon=lucide:gauge { cause "Gauge not zeroed each shift"}category environment "Environment" icon=lucide:cloud { cause "Hall temperature swings 10 degrees" cause "Humidity peaks after rain"}Effect: Housings crack at inspection.
People: 2 causes.
- Night shift skips the warm-up check
- Operators trained on the old press
Method: 2 causes.
- Cycle time cut by 8 percent
- Cooling step shortened
Machine: 4 causes.
- Mould temperature drifts (confirmed)
- Heater band worn
- Thermocouple out of calibration
- Ejector pins misaligned
Material: 2 causes.
- Resin batch moisture high
- New supplier for colourant
Measurement: 1 cause.
- Gauge not zeroed each shift
Environment: 2 causes.
- Hall temperature swings 10 degrees
- Humidity peaks after rain
Confirmed: Mould temperature drifts (Machine).
A slow build, with the head on the left
side=left puts the head at the left, for a page that reads from the problem outward. Two causes are marked, in two tones.
fishbone "Why the build takes 40 minutes" side=left desc="The causes of a slow continuous integration build. The fixtures rebuilt on every run are confirmed; the missing install cache is likely."effect "CI build takes 40 minutes"category deps "Dependencies" icon=lucide:package { cause "Install has no cache" tone=amber cause "Postinstall compiles native modules" { cause "Image library built from source" }}category tests "Tests" icon=lucide:list-checks { cause "Suites run one after another" cause "Fixtures rebuilt instead of cached" tone=red}category runners "Runners" icon=lucide:server { cause "Two CPU cores per job" cause "Cold disk on each run"}category config "Configuration" icon=lucide:settings { cause "Type check runs twice" cause "Lint runs on every file, not the changed ones"}Effect: CI build takes 40 minutes.
Dependencies: 3 causes.
- Install has no cache (confirmed)
- Postinstall compiles native modules
- Image library built from source
Tests: 2 causes.
- Suites run one after another
- Fixtures rebuilt instead of cached (confirmed)
Runners: 2 causes.
- Two CPU cores per job
- Cold disk on each run
Configuration: 2 causes.
- Type check runs twice
- Lint runs on every file, not the changed ones
Confirmed: Install has no cache (Dependencies); Fixtures rebuilt instead of cached (Tests).
The language
One statement to a line. Text is always in double quotes, options are key=value, and # starts a comment. A block opens with { at the end of a line and closes with } on a line of its own.
The header
fishbone "Title" side=right desc="<text>". The title and both options are optional. side= is right, the default, or left, and puts the head at that end of the spine. desc= is the plain-language description for assistive technology.
Statements
| Statement | Meaning | Example |
|---|---|---|
fishbone "Title" side=<right|left> desc="<text>" | The header. | fishbone "Why checkout errors rose" side=right |
effect "<text>" | The problem, drawn as the head. | effect "Checkout errors up 4x" |
category <id> "<Label>" tone=<tone> icon=<icon> { | A main bone and its card. Its block holds its causes. | category people "People" icon=lucide:users { |
cause <id> "<text>" tone=<tone> { | A cause in a category. The id is optional. With {, it holds sub-causes. | cause "Connection pool too small" tone=red |
desc "<text>" | The plain-language description; the same as desc= on the header. | desc "The causes the incident review found." |
The effect
The effect is the problem the causes lead to. Write it once, above the categories. It is drawn on a solid card at the end of the spine, the strongest thing in the picture. Without an effect line the title stands in, and without either the head reads Effect.
Categories
Each category is a bone. Categories alternate above and below the spine in the order written, from the tail toward the head, and are never reordered, because the order often carries meaning. A category's card holds its label and an optional icon; tone= colours the bone and the card.
Two common sets of categories are a good start:
| Set | Categories | For |
|---|---|---|
| 6M | People, Method, Machine, Material, Measurement, Environment | Manufacturing and operations |
| 4S | Surroundings, Suppliers, Systems, Skills | Services |
A software team often uses People, Process, Infrastructure, Code, and Dependencies. A category with no causes draws a bare bone, and lint warns about it.
Causes and sub-causes
A cause is a tick off its bone with its text beside it. A cause that ends with { holds sub-causes, drawn on shorter ticks from a stem under the cause, in a quieter type. A sub-cause holds nothing: a fourth level is refused with E140, and the hint suggests folding the detail into the sub-cause text.
Each bone is as long as its side's longest list of causes, so the cards stay in a row. Bones are spaced along the spine by the room their text needs, so causes never touch another bone or each other.
Confirmed causes
tone= on a cause or a sub-cause marks it as confirmed. Its text and tick are drawn in that tone, a dot marks where it meets the bone, and a key under the picture says "Confirmed cause". The text description lists every confirmed cause with its category. Use tone=red for the root cause and, if you need a second mark, tone=amber for a likely one.
Limits and warnings
| Limit | Value | What happens past it |
|---|---|---|
| Categories | 10 | E140 before any layout, with the advice to merge categories or split the diagram. |
| Causes in all, sub-causes included | 150 | E140. |
| Levels | 3 | E140 at the cause that opens a fourth level. |
| Categories before the warning | 6 | W200. |
| Causes on one bone before the warning | 8 | W200, at the category. |
| Cause width | 200px preferred, 260px hard, 3 lines | Text wraps, and a long word widens the text up to the hard width. Only past that is text cut with an ellipsis, with warning W203. |
| Sub-cause width | 160px preferred, 240px hard, 2 lines | The same. |
| Category label | 150px preferred, 240px hard, 2 lines | The same. |
| Effect | 180px preferred, 260px hard, 4 lines | The same. |
Every mistake comes back as a result with a code, a line, a column, and a hint. Warnings never stop the drawing.
| Code | When it fires | Fix |
|---|---|---|
E100 | A category with no id or no quoted label, a cause outside a category, a category inside another block, an effect inside a block, text with nothing in it, or a diagram with no categories. | Read the hint, which gives the form to write. |
E130 | A second effect, or an id used twice. | Write one effect, and give each id once. |
E133, E134 | A block that is never closed, or a } with no block to close. | Balance the braces, one } on its own line for each {. |
E136 | A side= that is neither right nor left. | Write side=right or side=left. |
E140 | More than 10 categories, 150 causes, or three levels. | Merge or split, as the hint says. |
E110, E121, E135, W208 | The shared codes: an unknown statement (a line of Mermaid names the converter), an unknown tone, an unknown option, and an unknown icon. | Read the hint. |
W200 | More than 6 categories, more than 8 causes on one bone, or a category with no cause. | Merge categories, keep the causes the evidence supports, or add the missing causes. |
W202 | The picture is wider than a Markdown column and its text would shrink. | Shorten the causes, or split the diagram. |
W203 | Text was cut with an ellipsis. | Shorten it, or move detail into a sub-cause. |
From Mermaid
Mermaid's Ishikawa diagram (ishikawa-beta, and ishikawa) converts to a fishbone diagram. Ask your agent to convert it, or use the convert_mermaid tool. The migration guide covers the converter in full. Mermaid gives the structure by indentation: the first line is the problem, the lines after it at the next level are categories, and deeper lines are causes.
ishikawa-beta Blurry Photo Process Out of focus Shutter speed too slow User Shaky hands Equipment LENS Inappropriate lens Dirty lens EnvironmentIt becomes:
fishbone "Blurry Photo"effect "Blurry Photo"
category process "Process" { cause "Out of focus" cause "Shutter speed too slow"}
category user "User" { cause "Shaky hands"}
category equipment "Equipment" { cause "LENS" { cause "Inappropriate lens" cause "Dirty lens" }}
category environment "Environment"| Mermaid | Plotwork | Report |
|---|---|---|
| The first line | effect "<text>", and the title when the Mermaid has none | none |
| A line at the next level | category <id> "<text>" {, with an id made from the text, or c1 and so on when the text makes none | none |
| A line under a category | cause "<text>" | none |
| A line under a cause | A sub-cause | none |
| A line deeper than a sub-cause | A sub-cause of the cause above it | M204 |
Front matter title:, accTitle:, accDescr: | The title and desc= | none |
<br/>, other HTML, and entities in a line | Removed or decoded | M205 |
| A line left with no text | Dropped, and the lines under it move up | M216 |
Front matter config: and %%{init}%% | Dropped | M200 |
| Text after the header word | Nothing is converted | M110 |
| No category | Nothing is converted | M103 |
| More than 10 categories or 150 causes | The rest is not read | M102 |
Mermaid has no way to mark a confirmed cause, so after converting, add tone=red to the root cause, an icon= to each category, and ids that say what each category is.
See also
| Doc | Why |
|---|---|
| Writing diagrams | The flow, sequence and schema languages, and the rules every kind shares |
| Mind maps | A central idea and the branches that grow from it, when the ideas are not causes |
| Tree diagrams | A hierarchy drawn as an outline or an org chart |
| Quadrant charts | Rank the causes you found by likelihood and impact |
| Migrating from Mermaid | Convert existing Mermaid diagrams, and what is dropped |
| Language reference | Every kind, node type, option and diagnostic |
| Diagram kinds | The kinds Plotwork draws and the header of each |