Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork8.1k
DOC: add section about how to write good error messages#25292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Uh oh!
There was an error while loading.Please reload this page.
doc/devel/contributing.rst Outdated
| While this does tell the user what variable and value Matplotlib rejected, it still | ||
| does not tell them why. | ||
| An example of a **best** error message :: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Throwing your advice back to you, what about starting with the recommended best practice so that it won't get lost in skimming/fatigue? Then if it's still necessary, discuss unpack why the bad is bad - but honestly I'm not sure it's necessary given I think the paragraph under here does a good job of explaining why folks should do it this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Agree with this - the first draft is pretty verbose....
doc/devel/contributing.rst Outdated
| Which tells the user what input in broken, what was passed in, and the reason | ||
| why the value was invalid. All of this together gives the user the best chance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is a personal preference, but I like this sort of info broken out into a list:
We recommend writing an error message that states:
- which parameter is raising the error
- what value was passed
- why the value is incorrect
doc/devel/contributing.rst Outdated
| In cases like this it may be possible to get into an interactive debugger and | ||
| from reading the stack trace sort out right local variable to check is to start | ||
| to sort out what went wrong. However, without access to the running process the user |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
After theand, this sentence kind of gets a bit muddled.
doc/devel/contributing.rst Outdated
| Internal helpers | ||
| ~~~~~~~~~~~~~~~~ | ||
| Matplotlib has number of helper functions in the ``matplotlib._api`` module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
| Matplotlib has number of helper functions in the ``matplotlib._api`` module | |
| Matplotlib hasanumber of helper functions in the ``matplotlib._api`` module |
doc/devel/contributing.rst Outdated
| ~~~~~~~~~~~~~~~~ | ||
| Matplotlib has number of helper functions in the ``matplotlib._api`` module | ||
| named as ``check_*`` which provide nice error messages for very common checks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
| named as ``check_*`` which provide nice error messages forverycommon checks | |
| named as ``check_*`` which provide nice error messages for common checks |
very seems superfluous?
doc/devel/contributing.rst Outdated
| This message tells the user what (local) variable Matplotlib checked was and | ||
| what value was passed in which can help users rapidly find bugs in their own | ||
| code. For example if they expected to have passed in an integer but the error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
| code. For example if they expected to have passed in an integer but the error | |
| code. For example, if they expected to have passed in an integer but the error |
doc/devel/contributing.rst Outdated
| This message tells the user what (local) variable Matplotlib checked was and | ||
| what value was passed in which can help users rapidly find bugs in their own | ||
| code. For example if they expected to have passed in an integer but the error | ||
| messages reports the string ``'aardvark'``, they may know where in their code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
| messages reports the string ``'aardvark'``, they may know where in their code | |
| message reports the string ``'aardvark'``, they may know where in their code |
oscargus commentedFeb 23, 2023
I'm missing info about dropping punctuation characters and if an error message should be in Sentence case or nor. |
anntzer commentedFeb 23, 2023
Highly nitpicky, but my personal(?) view is to do what cpython does: i.e. no leading capital and no trailing punctuation. |
anntzer commentedFeb 23, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I agree with others that this seems pretty verbose (though a good idea to document); a first try at editing (while keeping most of your wording) gives me Error messages should err on the side of being verbose, descriptive, andspecific about what went wrong. They should be informative enough so that atypical user (not an expert of our API) can understand, debug, and fix theirproblem based solely on the message, without the need to consult the onlinedocumentation.For example, input validation errors should include, where possible,information about which input is invalid, what value was passed in, and why thevalue is invalid, e.g. :: raise ValueError(f"{value=!r} is invalid, value must be a positive integer")This message helps the user to quickly diagnose and fix their problem.Remember that many other libraries are implemented on top of Matplotlib, andtherefore ``value`` may not even have been directly passed by the user, butrather generated in some intermediate layer. In such cases, this kind ofhighly explicit messages can be particularly useful, compared to shortermessages such as :: raise ValueError("invalid value") |
tacaswell commentedMar 31, 2023
I took@anntzer 's wording whole sale and applied the other changes. |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
58df24d to2129084CompareCo-authored-by: Elliott Sales de Andrade <quantum.analyst@gmail.com>Co-authored-by: Antony Lee <anntzer.lee@gmail.com>Co-authored-by: Oscar Gustafsson <oscar.gustafsson@gmail.com>
2129084 to5e621a4Comparestory645 commentedOct 9, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Can you leave licensing as the last entry since it's not really like the others? |
| information about which input is invalid, what value was passed in, and why the | ||
| value is invalid, e.g. :: | ||
| raise ValueError(f"{value=!r} is invalid, value must be a positive integer") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I suggest to include the parameter name. It's not always needed, but good for educational purposes. For example
matplotlib/lib/matplotlib/text.py
Lines 1263 to 1264 in6e95994
| raiseValueError("rotation must be 'vertical', 'horizontal' or " | |
| f"a number, not{s}") |
Edit, oh maybe you meanvalue as the parameter name? In that case I would use a more targeted name for the example.
We may also consider adopting a policy to enquote parameter names in single ticks. While there's no universal convention, this is the closest I have found for a pattern, see e.g.
| messages such as :: | ||
| raise ValueError("invalid value") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Maybe inline to de-emphasize?
| messages such as :: | |
| raise ValueError("invalid value") | |
| messages such as ``raise ValueError("invalid value")``. |
When skimming the section, you primarily notice the heading and the two code blocks, giving the impression that both are relevant. There's no indication that one is a negative example.

| ..currentmodule::matplotlib | ||
| ..autosummary:: | ||
| :toctree: _as_gen | ||
| :template: autosummary.rst | ||
| :nosignatures: | ||
| _api.check_isinstance | ||
| _api.check_in_list | ||
| _api.check_shape | ||
| _api.check_getitem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This generates API documentation resulting in duplication
- https://output.circle-artifacts.com/output/job/99a2d267-7d06-42e8-9318-237d42c8dd16/artifacts/0/doc/build/html/devel/_as_gen/matplotlib._api.check_isinstance.html#matplotlib._api.check_isinstance
- https://output.circle-artifacts.com/output/job/99a2d267-7d06-42e8-9318-237d42c8dd16/artifacts/0/doc/build/html/api/_api_api.html#matplotlib._api.check_isinstance
The best would be if one could tell autosummary not to create new API doecumentation and just link to the existing ones, but I think that is not possible (correct me if I'm wrong).
As a workaround, I'd create a manual table or bullet list (with or without copied/hard-coded description).
An alternative with a little more work would be to structurehttps://matplotlib.org/stable/api/_api_api.html into topic sections and and link to the section on validation/error handling.
| Internal helpers | ||
| ~~~~~~~~~~~~~~~~ | ||
| Matplotlib has a number of helper functions in the ``matplotlib._api`` module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
link
| Matplotlib has a number of helper functions in the ``matplotlib._api`` module | |
| Matplotlib has a number of helper functions in the `matplotlib._api` module |
| consistent across the library. Use them in your own code at your own risk, we | ||
| consider them private API and reserve the right change them with no notice on | ||
| any release. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
| consistent across the library. Use them in your own code at your own risk, we | |
| consider them private API and reserve the right change them with no notice on | |
| any release. | |
| consistent across the library. |
I would leave this out here. It's in an underscored module and the module docstring also explicitly states this.
PR Summary
After leaving a comment to make error messages verbose I felt inspired to write it up for the docs...
Adding generated API docs for the private API might be a bit controversial, but I think on net it is the right thing to do so that we if we do remove them we can be sure that the docs do not still advocate for their use and saying "there are some
check_*functions" felt too vague).