# Config static analysis

**URL:** <https://klipper.discourse.group/t/config-static-analysis/22290>\
**Category:** Developers\
**Created:** [March 1, 2025, 10:30pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290 "2025-03-01T22:30:06Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![labradorius](https://avatars.discourse-cdn.com/v4/letter/l/9fc29f/32.png) [@labradorius](https://klipper.discourse.group/u/labradorius)\
**Post date:** [March 1, 2025, 10:30pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/1 "2025-03-01T22:30:06Z")

</div>

I am currently looking into the Klipper codebase to improve the area related to the config. My motivation towards doing so is that I have a complex set of config files that are joined together using imports and I want to better understand the end-state of the config as Klipper sees it.

Towards that end I want to add a tool which parses the config file and allows the end-user to do things with it, such as display it all as a single file, for troubleshooting, annotating which line came from which file, and possibly going as far as adding new features to the config language like supporting multiple units for some properties (e.g. mm and cm) though I doubt that would be accepted.

I did some searching, but I couldn’t find much discussion on it. Is there any prior work in this area? Would a tool like this be accepted to upstream?

---

<div class="post-metadata">

**Author:** ![Sineos](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/sineos/32/18_2.png) [@Sineos](https://klipper.discourse.group/u/Sineos)\
**Post date:** [March 1, 2025, 10:51pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/2 "2025-03-01T22:51:04Z")

</div>

Not sure that I understand what you are aiming at and what the overarching goal or benefit would be. Could you highlight it with some concise examples?

> [@labradorius](#):
>
> I want to better understand the end-state of the config as Klipper sees it.

In my view, this is quite simple:

- The `klippy.log` will always reflect the config as parsed and used by Klipper.
- Adding the same config section multiple times will either:
  - Result in an error, notifying you that this is not possible.
  - Overwrite the previous declaration with the one that has been parsed last.

---

<div class="post-metadata">

**Author:** ![Sineos](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/sineos/32/18_2.png) [@Sineos](https://klipper.discourse.group/u/Sineos)\
**Post date:** [March 1, 2025, 11:12pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/3 "2025-03-01T23:12:49Z")

</div>

Maybe to add: What I tried and failed due to my miserable coding skills would have been a linter for Klipper config, similar to ShellCheck, ESLint, etc.

It should have covered items like:

- Missing indentation in macros
- Settings that are not recommended, like `hold_current` or switching between Stealth Chop and Spread Cycle mid-print
- Duplicate settings that would get overwritten
- Classified as Notes, Warnings, or Errors
- And so on

In the best case, as a web application so that users have an easy way to quality check their configs.

Not sure if you are suggesting something along these lines. If yes, I’m all ears.

---

<div class="post-metadata">

**Author:** ![labradorius](https://avatars.discourse-cdn.com/v4/letter/l/9fc29f/32.png) [@labradorius](https://klipper.discourse.group/u/labradorius)\
**Post date:** [March 1, 2025, 11:20pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/4 "2025-03-01T23:20:40Z")

</div>

Thanks for that info! I’d like to update the config docs to share that info about how it behaves! That will help a lot!

Regarding the practical benefits, I’m an enthusiast of programming languages and parsers/compilers/static analysis, so I’m hoping my interest can be helpful to Klipper.

Yeah, that sounds like schema validation! It’s a step I would like to add after the config is parsed.

---

<div class="post-metadata">

**Author:** ![labradorius](https://avatars.discourse-cdn.com/v4/letter/l/9fc29f/32.png) [@labradorius](https://klipper.discourse.group/u/labradorius)\
**Post date:** [March 1, 2025, 11:24pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/5 "2025-03-01T23:24:14Z")

</div>

If we wanted to make it available as a web application, is that something I would cooperate with the Mainsail project on adding?

---

<div class="post-metadata">

**Author:** ![3dcoded](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/3dcoded/32/20297_2.png) [@3dcoded](https://klipper.discourse.group/u/3dcoded)\
**Post date:** [March 2, 2025, 1:02am UTC](https://klipper.discourse.group/t/config-static-analysis/22290/6 "2025-03-02T01:02:14Z")

</div>

If I’m understanding correctly, you want to make an addition to Klippy for config schema validation. If so, you’ll have to create the Klippy extra (or modify the existing `configfile.py` module). Then, you could create an addition to Mainsail to access the messages from your custom module.

So the flow of information would be Configuration → Validation code → `get_status()` → Moonraker → Mainsail.

The `get_status()` part (a function in your extra) is important to expose the information through Moonraker. Basically it just returns a JSON-friendly dictionary and it can be accessed through macros or UI’s.

I wrote a tutorial for Klippy extras [here](https://3dcoded.github.io/DynamicMacros/extras/extras-intro/) if you want help getting started.

---

<div class="post-metadata">

**Author:** ![Sineos](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/sineos/32/18_2.png) [@Sineos](https://klipper.discourse.group/u/Sineos)\
**Post date:** [March 2, 2025, 3:57pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/7 "2025-03-02T15:57:19Z")

</div>

FWIW and without being the authority, I would keep clear of Klipper’s config parsing in order to:

- Avoid the danger of regressions. History has shown that this is a sensitive area.
- Adding features and further complexity also increases the maintenance burden in this area.

From experience, there are three groups of “static” config issues:

1. Issues preventing Klipper’s start in the first place, e.g., wrong or incomplete serial-paths in the `[mcu]` section. There are more such problems, and typically their error messages can be cryptic.
2. Issues that “silently” might affect operation, e.g., [TMC drivers - Klipper documentation](https://www.klipper3d.org/TMC_Drivers.html#prefer-to-not-specify-a-hold_current) and following chapters.
3. Issues that only hit when a certain function is called, e.g., [SAVE\_CONFIG section 'bltouch' option 'z\_offset' conflicts with included value](https://klipper.discourse.group/t/save-config-section-bltouch-option-z-offset-conflicts-with-included-value/6640).

To catch all three, the best thing would be some external validation that “imports” Klipper’s parsing rules.  
An “extra” like proposed by @3dcoded would be nice as well, but will likely not work for number 1.

My dream would have been:

- Static analysis with a flexible rule engine that can be easily extended.
- Likely stand-alone. Being part of either Klipper, Moonraker, or the web interfaces always requires a successful start of Klipper.
- Proposals on how to fix certain issues and useful hints, e.g., “Often the BLTouch pin requires the declaration of a pull-up via `^`.”
- As a cherry on the cake: Some beautifier functionality, like indentation, etc.

---

<div class="post-metadata">

**Author:** ![labradorius](https://avatars.discourse-cdn.com/v4/letter/l/9fc29f/32.png) [@labradorius](https://klipper.discourse.group/u/labradorius)\
**Post date:** [March 2, 2025, 9:34pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/8 "2025-03-02T21:34:07Z")

</div>

I spent a few hours yesterday digging deeper into the Klippy code and extras and I learned a lot. I learned that Klippy is not entirely responsible for parsing the config. Instead, each module parses the value from a key in its own config section. Changing how that works in any way would be quite disruptive, too disruptive for a first improvement.

So, yeah I can better understand your thinking that an external tool, in its own codebase entirely. It would take as input the printer.cfg and do its analysis, outputting to the terminal or a file or whatever. Once that is mostly done, I could look into a frontend like Mainsail to see how to surface that information there.

Thanks for your help on this! It should be a fun project!

---

<div class="post-metadata">

**Author:** ![Sineos](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/sineos/32/18_2.png) [@Sineos](https://klipper.discourse.group/u/Sineos)\
**Post date:** [March 3, 2025, 6:31am UTC](https://klipper.discourse.group/t/config-static-analysis/22290/9 "2025-03-03T06:31:19Z")

</div>

Looking forward to seeing your results. A generic way to catch the most obvious quality issues in a config would surely help a lot of users.

If you have something to start with, I can help create some rules for common issues. Not everything is caught by the parsing rules in Klipper. There are quite a few regular issues that seem valid but are essentially not. For example, points 2 and 3 above.

---

<div class="post-metadata">

**Author:** ![labradorius](https://avatars.discourse-cdn.com/v4/letter/l/9fc29f/32.png) [@labradorius](https://klipper.discourse.group/u/labradorius)\
**Post date:** [March 11, 2025, 7:05am UTC](https://klipper.discourse.group/t/config-static-analysis/22290/10 "2025-03-11T07:05:10Z")

</div>

Hey @Sineos, where is the best place to data mine issues people have with the config file? I’m currently finishing up collecting from the GitHub issues, but that’s a small data set.

---

<div class="post-metadata">

**Author:** ![Sineos](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/sineos/32/18_2.png) [@Sineos](https://klipper.discourse.group/u/Sineos)\
**Post date:** [March 11, 2025, 9:49am UTC](https://klipper.discourse.group/t/config-static-analysis/22290/11 "2025-03-11T09:49:08Z")

</div>

Well, this place and the official Klipper Discord should definitely contain the highest concentration of such topics.

---

<div class="post-metadata">

**Author:** ![3dcoded](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/3dcoded/32/20297_2.png) [@3dcoded](https://klipper.discourse.group/u/3dcoded)\
**Post date:** [March 12, 2025, 12:42am UTC](https://klipper.discourse.group/t/config-static-analysis/22290/12 "2025-03-12T00:42:20Z")

</div>

@labradorius ,

I’ll be following this development. Let me know if you need help testing!

---

<div class="post-metadata">

**Author:** ![Sineos](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/sineos/32/18_2.png) [@Sineos](https://klipper.discourse.group/u/Sineos)\
**Post date:** [March 13, 2025, 5:28pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/13 "2025-03-13T17:28:01Z")

</div>

> [@labradorius](#):
>
> best place to data mine issues people

If you are interested, I can add topics that I stumble upon here in the thread, for example:

- No x/y offsets in the [probe] section → [Tilt and bed besh don't seem to correlate](https://klipper.discourse.group/t/tilt-and-bed-besh-dont-seem-to-correlate/22399)
  - For [probe] sections it should be a warning
  - For [bltouch] sections an error

- Wrong format of the serial → [Da Vinci MCU unable to connect - #9 by EleriLove](https://klipper.discourse.group/t/da-vinci-mcu-unable-to-connect/22324/9)
  - A bit tricky, e.g. [Issues flashing the printer board](https://klipper.discourse.group/t/issues-flashing-the-printer-board/14015#obtaining-the-boards-serial-7)
  - Sometimes, `/dev/serial/by-id/` or `/dev/serial/by-path/` is omitted
  - [MCU Connection issue after flashing ADXL345 v2.0](https://klipper.discourse.group/t/mcu-connection-issue-after-flashing-adxl345-v2-0/22175)

- Having certain sections multiple times: [Unable to save printer.cfg, log shows old config after "save and restart"](https://klipper.discourse.group/t/unable-to-save-printer-cfg-log-shows-old-config-after-save-and-restart/21402)
- Blanks in fron to settings where no blanks belong: [SAVE\_CONFIG section ‘bltouch’ option ‘z\_offset’ conflicts with included value - #11 by Sineos](https://klipper.discourse.group/t/save-config-section-bltouch-option-z-offset-conflicts-with-included-value/21188/11)
- `enable_pin` not inverted, multiple endstop definitions: [Why Won't my Z Steppers Move?](https://klipper.discourse.group/t/why-wont-my-z-steppers-move/18823)
- Wrongly set mesh boundaries: [Move Out Of Range Issue pls help - Bed Mesh Calibrate](https://klipper.discourse.group/t/move-out-of-range-issue-pls-help-bed-mesh-calibrate/22449)

Just as a first start.

---

<div class="post-metadata">

**Author:** ![labradorius](https://avatars.discourse-cdn.com/v4/letter/l/9fc29f/32.png) [@labradorius](https://klipper.discourse.group/u/labradorius)\
**Post date:** [March 14, 2025, 2:15am UTC](https://klipper.discourse.group/t/config-static-analysis/22290/14 "2025-03-14T02:15:48Z")

</div>

I published the current state of the project here, in case you’re interested in contributing, but I’ll warn you that it is liable to change.  
[https://github.com/chexxor/klipper-cfg-linter](https://github.com/chexxor/klipper-cfg-linter)

There are only a few linting rules in there, in the klipperlint/rules directory, to explore how those might look. I haven’t deeply considered the format of them, like how we should store them, their format, etc., so I look for input on that.

---

<div class="post-metadata">

**Author:** ![3dcoded](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/3dcoded/32/20297_2.png) [@3dcoded](https://klipper.discourse.group/u/3dcoded)\
**Post date:** [March 14, 2025, 12:29pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/15 "2025-03-14T12:29:25Z")

</div>

@labradorius ,

Thank you for letting me know. I tested it on my setup, and was able to locate a couple bugs. I submitted a PR [#1](https://github.com/chexxor/klipper-cfg-linter/pull/1).

Overall, this looks really well done so far.

---

<div class="post-metadata">

**Author:** ![bozzo](https://avatars.discourse-cdn.com/v4/letter/b/7993a0/32.png) [@bozzo](https://klipper.discourse.group/u/bozzo)\
**Post date:** [March 16, 2025, 12:18pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/16 "2025-03-16T12:18:25Z")

</div>

@labradorius,

this looks like a fun project!

you can easily improve your test setup by adding a bunch of real-world known-good configs, to check the rules for false positives, because false positives are what discourages people from using such tools…

for example, by leveraging sample configs from klipper, from 3d printer projects that publish sample configs (voron, …), and if you don’t know the klippain project maybe worth having a look to torture test your parser and include resolver :).

I had a brief look at your rules and the pin rule doesn’t seem to be quite in line with the [klipper documentation](https://www.klipper3d.org/Config_Reference.html#format-of-micro-controller-pin-names), for example that regex will not accept a `^!PA3` nor does it know about [multi-mcu pin names](https://www.klipper3d.org/Config_Reference.html#mcu-my_extra_mcu) or about [pin aliases](https://www.klipper3d.org/Config_Reference.html#board_pins)

which brings me to my unsolicited opinion: most value-add rules will require code, so having yaml files around instead of one python module per rule is not an obvious benefit.

---

<div class="post-metadata">

**Author:** ![labradorius](https://avatars.discourse-cdn.com/v4/letter/l/9fc29f/32.png) [@labradorius](https://klipper.discourse.group/u/labradorius)\
**Post date:** [March 16, 2025, 7:03pm UTC](https://klipper.discourse.group/t/config-static-analysis/22290/17 "2025-03-16T19:03:12Z")

</div>

@bozzo I appreciate your feedback! Regarding the rule format, I agree. I really wanted the rules to be formatted in a way that non-programmers could contribute. There are some simple rules that could be formatted declaratively using a YAML format, but I can see it quickly becoming a small language of its own, which was what I wanted to avoid.

I can look into some inference techniques, so we could give some examples of config properties that are valid and invalid, then have an inference tool derive a rule from that. That would be a neat way to do them, assuming it would be reliable enough.
