How to explain an error message in a post

Some of the most useful technical posts ever written are about a single error message. Someone hits it, pastes it into a search engine, and lands on a page that explains what it means, why it happened and how to make it go away. If that page is good, the reader is back to work in five minutes. If it is a list of things to try, they may be there all evening.
Writing about an error well is a skill of its own. This is the structure we suggest, using one common Python error as the running example.
Quote the error exactly, as text
The reader who finds your post has the error in front of them, and they will compare it with yours character by character. Give them the complete message, copied from the terminal, in a code block. Not a paraphrase, not a screenshot:
Traceback (most recent call last):
File "/home/dev/app/fetch.py", line 1, in <module>
import requests
ModuleNotFoundError: No module named 'requests'Text matters for three reasons. Search engines can index it, so the post can be found at all. Readers can search the page for the exact line they are seeing. And they can copy parts of it, such as a file path or an error code, into their own commands. A screenshot does none of those things.
Keep the surrounding lines that help with diagnosis, such as the file and line number, and trim what does not, such as fifty identical lines of a stack trace. If you trim, say so with a short note, so nobody wonders whether they are looking at a different error. Replace anything private, like user names in paths or tokens in URLs, with obvious stand-ins.
Say which program is talking
Error messages come from somewhere, and readers often do not know where. Is this the shell, the interpreter, the package manager or the library? The answer decides where to look next. In the example, the message comes from the Python interpreter itself: it reached import requests, searched every directory on its module path and did not find a package called requests.
One sentence like that does more than it seems. It tells the reader that the code in fetch.py is probably fine, that the network is not involved, and that the problem lies in what is installed where. It narrows the search before you have even got to the cause.
Explain the cause in one plain sentence
Lead with the most likely cause, stated simply, before any detail. For this error, it is usually this: the package was installed for a different Python than the one running the script.
That happens more easily than it sounds. A system can have several Python interpreters, and each has its own set of installed packages. The pip command on your path may belong to one interpreter while python3 belongs to another, or a virtual environment may have been active when you installed the package and not when you ran the script. Then give the reader a way to check it, rather than asking them to take your word for it:
python3 -c "import sys; print(sys.executable)"
python3 -m pip --versionThe first command prints the full path of the interpreter that runs when you type python3. The second prints the version of pip that belongs to that same interpreter, followed by where it lives and which Python it serves. If the package was installed with a plain pip command that points somewhere else, the mismatch is now visible.
Give the fix, then a way to confirm it
Once the cause is clear, the fix should follow from it so naturally that the reader could almost have guessed it. Install the package for the interpreter that actually runs the script. The safest way is to create a virtual environment for the project and install inside it:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install requestsRunning pip as python -m pip guarantees that the package goes to the interpreter you are about to use, whatever the plain pip command points to. Then end the section with a check that proves the fix worked, independently of the reader’s own script:
python -c "import requests; print(requests.__version__)"If that prints a version number, the import problem is solved. If the script still fails after this, the reader knows the cause lies elsewhere, which is useful information too. A fix without a confirmation step leaves people unsure whether they did it right.
Cover the near misses
Many errors have cousins: messages that look similar or appear in the same situation, but mean something different. Readers who land on your post may have one of those instead, so a short section on them saves a second search.
For this example there is an important one. On recent Debian and Ubuntu releases, installing into the system Python with pip is refused, and the message starts like this:
error: externally-managed-environmentThat is not a bug and not the same problem. The operating system marks its Python as managed by the system package manager, so that pip cannot overwrite files the system depends on. The virtual environment from the previous section avoids it, because pip then installs into the project’s own directory. Mentioning this matters, because a reader who tried python3 -m pip install requests on such a system will hit exactly this message next.
Another cousin is ImportError with a message about a name that cannot be imported from a module. There, the package was found but does not contain what the code asked for, which often points to a version mismatch, or sometimes a circular import, rather than a missing install. One or two sentences per near miss are enough; link to a fuller explanation if you have one.
Shape the post so it can be found and skimmed
Put the error text in the title or the first lines of the post, because that is what people search for. A title like “Fixing ModuleNotFoundError when pip installed the package” is more useful than “A Python packaging puzzle”. Keep the order the same as above: the message, where it comes from, the cause, the fix and its check, the near misses. A reader in a hurry can then jump straight to the fix, and a reader who wants to understand can read from the top.
Say which versions and systems you saw the error on, because error text changes between releases. When it does change, update the post and note what changed; our post on updating a technical post covers how. For formatting the commands in your fix so they paste cleanly, see Code blocks readers can copy and paste safely. And if a reader found a different cause, the comments under each post are open to anyone with a name, reviewed before they appear, as the help pages explain.




Comments 0
Comments are reviewed before they appear. Oldest first.
No comments yet. Spotted a typo, a better flag, or a step that failed for you? Say so below.