Skip to content

Report unusable rule literals as rule and value errors - #92

Open
JingHao-Leon wants to merge 2 commits into
decryptus:masterfrom
JingHao-Leon:fix/rule-literal-value-errors
Open

JingHao-Leon wants to merge 2 commits into
decryptus:masterfrom
JingHao-Leon:fix/rule-literal-value-errors

Conversation

@JingHao-Leon

@JingHao-Leon JingHao-Leon commented Oct 20, 2026 •

Copy link
Copy Markdown

What broke

A monitoring rule whose literal cannot be used left the rule engine as an unhandled ValueError. The historical runtime CLI answered with exit status 150 — the status reserved for "unexpected exception" — and logged a full Python traceback, instead of reporting the rule error with its documented status.

Two literals were affected:

  • a size unit the parser cannot resolve, for example 100 mb (the size parser expects MB, MiB, kB, B, …);
  • a literal that does not fit the measured value's type, for example a decimal against a byte-valued resource such as mem_usage, or a word against a percentage resource.

mem_usage, mem_limit, io_read, io_write, net_rx, net_tx and pid are measured as integers, so any decimal or word literal compared against them raised ValueError while the condition was evaluated. The same rule stored in the configuration file was already reported cleanly, so only the command line path was affected.

This change makes the unusable literal a rule syntax error (140) when the expression is parsed, and a value error (110) when the literal does not fit the measured value's type.

Root cause

  • monit_docker/adapters/rules.py:95 (also :92, :50 and :47): the sized literal was handed to bitmath.parse_string() without handling the ValueError it raises for an unsupported unit, so the failure left the parser as a raw exception.
  • monit_docker/core/rules.py:69 (and :71): the expected value was coerced with type(actual)(condition.value), but only TypeError was caught at :72. A literal that cannot be converted raised ValueError, which was not handled, so the failure left the evaluator as a raw exception.

How verified

  • Command: python -m unittest discover -s tests -v (Python 3.13.9, repository dependencies installed in a local virtual environment).
    • Before this change: Ran 407 tests in 39.960s / FAILED (failures=1, errors=5, skipped=18).
    • After this change: Ran 413 tests in 40.045s / FAILED (failures=1, errors=5, skipped=18).
    • The failing set is byte-for-byte identical before and after: one packaging test that needs GNU sed -i and five tests that need Linux /proc, GNU stat -f -c or a TTY. Six new tests are added (four in tests/test_rule_literals.py, two in tests/test_monit_docker.py).
  • Command: python .github/scripts/check-test-collection.py --runner unittest tests.
    • Result: Collection verified: 413 declarations, 413 cases (unittest).
  • The new tests fail on the parent commit and pass on this branch. With the source change reverted, python -m unittest tests.test_rule_literals tests.test_monit_docker reports FAILED (failures=2, errors=7).
  • Command line, on this branch:
    • monit-docker monit --cmd-if 'mem_usage > 100 mb ? restart' exits 140 and prints unsupported unit in expression value: '100 mb' without a traceback.
    • monit-docker monit --cmd-if 'mem_usage > 1.5 ? restart' exits 110 without a traceback.
    • Before this change both commands exited 150 with a Python traceback.

CI

The pull request's workflow is waiting for a maintainer to approve it: the Docker Hub run
(dockerhub.yml) finished with action_required and 0 jobs, so the test suite has not run on
GitHub for this pull request. The numbers above come from running the same suite locally against
this branch.

The other workflows are not triggered by this diff: grafana-screenshots.yml and
ui-acceptance.yml are path-filtered to files this change does not touch, and tests.yml and
upgrades.yml are workflow_call-only — they run as jobs of dockerhub.yml once it is
approved.

Fixes #91

This change was prepared with the assistance of an AI coding agent.

An unsupported size unit and a literal that does not fit the measured
value's type both escape as an unhandled ValueError today, so the
historical runtime CLI answers with the reserved unexpected-exception
status instead of a rule or value error.
An unsupported size unit reached bitmath.parse_string() unguarded and
raised a raw ValueError, so the historical runtime CLI answered with
the reserved unexpected-exception status 150 and a traceback.

Resolve a sized literal through one helper that turns the parser's
error into RuleSyntaxError, which the CLI already maps to the
documented rule syntax status 140. The evaluator only guarded
TypeError when coercing a literal to the measured value's type, so a
decimal or non-numeric literal against a byte-valued resource also
escaped as a ValueError; guard ValueError as well and report the
already intended value error 110.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unusable rule literals escape as unhandled exceptions and exit 150

1 participant