Skip to content

Fix Fleet Dashboard 500 and other __() calls given too few values - #60

Merged
TheWitness merged 1 commit into
developfrom
fix/fleet-dashboard-sprintf-500
Oct 17, 2026
Merged

TheWitness merged 1 commit into
developfrom
fix/fleet-dashboard-sprintf-500

Conversation

@TheWitness

Copy link
Copy Markdown
Member

Description

Fixes the Fleet Dashboard returning a 500 error, and the same mistake in 14 other translated strings.

Cacti's __() formats a string as soon as it is given more than the text: the text domain counts as just another sprintf value. The plugin called it as sprintf(__('%s of %s rated', 'apcupsd'), $load, $capacity), so __() itself ran sprintf('%s of %s rated', 'apcupsd'), which has one value for two placeholders and throws ArgumentCountError ("3 arguments are required, 2 given", the exact error in #59).

Every string with a placeholder now passes its values to __() before the text domain, with no sprintf() wrapper:

__('%s of %s rated', $load, $capacity, 'apcupsd');

15 call sites in includes/dashboard.php (8), includes/nut.php (4), upses.php (2) and poller_apcupsd.php (1). The string literals are unchanged, so the translation template does not change.

Besides the dashboard crash this fixes:

  • Silent wrong text. Single-placeholder strings did not crash but printed the text domain instead of the value: the gauge summaries read "min apcupsd", and the NUT messages read "did not answer within apcupsd seconds", "reported an error: apcupsd" and a UPS "named apcupsd".
  • Poller crash on an unreachable NUT server. apcupsd_nut_query() builds its "Unable to connect to the NUT server %s: %s" message the same way, so a refused or unreachable upsd threw the same ArgumentCountError inside the background poller. With its output discarded, the poller died silently: no status for that UPS, the remaining UPSes not polled, and no APCUPSD STATS line. That matches the symptoms in NUT UPSes polling is not working #57.

Related Issue

Fixes #59

Related to #57 (the poller crash above is the likely cause of its "Unknown" status and empty log, but I have not been able to confirm that on a real Cacti install).

Motivation and Context

The test bootstrap's __() stub just returned the text, so sprintf(__(...), ...) always worked in tests and nothing could catch this. The stub now mirrors Cacti's __(): it formats at once, the trailing domain is one more value, and too few values throw. A new test scans the plugin's source with PHP's tokenizer and fails if any __() or __esc() call has a placeholder with only the text domain after it, so the mistake cannot come back unnoticed.

How Has This Been Tested?

  • php -l is clean on every changed PHP file.
  • Pest (Windows, PHP 8.4, Pest 5): 225 passed. The 4 warnings are existing socket-timeout warnings from NutClientTest.
  • New tests/Unit/I18nPlaceholderTest.php covers the source scan (and that the scanner flags the broken form), the Cacti-faithful formatting, and the NUT error messages. The same scan found exactly these 15 sites on the unmodified develop code.
  • Not run inside a real Cacti, so I have not loaded the Fleet Dashboard page itself. The fix is based on Cacti's __() source and the stack trace in The NUT UPS seems to be working again, but the Fleet Dashboard tab shown a 500 error #59.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation repository accordingly.

Cacti's __() formats at once when given more than the text, and the text domain counts as a sprintf value, so sprintf(__('%s of %s rated', 'apcupsd'), ...) threw an ArgumentCountError (the dashboard 500) and single-placeholder strings printed 'apcupsd' instead of the value. The same pattern in the NUT connect message crashed the poller whenever upsd was unreachable. Pass the values to __() before the text domain at all 15 sites.

Make the test __() stub mirror Cacti, and add a source scan that fails if the mistake returns.

Fixes #59

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 17, 2026 14:41
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused corrections match Cacti’s formatting contract, with regression coverage and no unresolved findings.

No open issues 🎉

What changed in this PR

Fixes translation formatting across the apcupsd plugin, addressing the Fleet Dashboard error in #59 and a possible cause of the polling failure in #57.

Changes:

  • Corrects 15 translation calls to pass values before the text domain.
  • Updates translation stubs and adds regression tests.
  • Documents the fixes in the changelog.
File Description
upses.php Fixes Graph Automation messages.
tests/​Unit/​I18nPlaceholderTest.php Adds placeholder and NUT message regression tests.
tests/​bootstrap-unit.php Makes translation stubs format supplied values.
poller_apcupsd.php Fixes the apcaccess timeout message.
includes/​nut.php Fixes NUT error and timeout messages.
includes/​dashboard.php Fixes gauge summaries and estimated-load formatting.
CHANGELOG.md Documents crashes and incorrect messages addressed.

Review effort: Balanced

@TheWitness
TheWitness merged commit bc49206 into develop Oct 17, 2026
6 checks passed
@TheWitness
TheWitness deleted the fix/fleet-dashboard-sprintf-500 branch October 17, 2026 22:57
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.

The NUT UPS seems to be working again, but the Fleet Dashboard tab shown a 500 error

3 participants