July 10, 2026

The Missing Save Button That Wasn't a Permissions Problem

A MediaWiki Save button vanished after a PHP 8 upgrade with no error in sight. The real cause wasn't the PHP version — it was one broken line in EditPage.php.

  • MediaWiki
  • PHP
  • Debugging
Illustration of a dashed, half-missing button with a stray comma

The report

A colleague pinged me: she could open any page on our internal MediaWiki wiki, edit the text, fill in the summary — but the Save button was gone. Just a “Cancel” link sitting where the buttons used to be. Her first guess was the obvious one: “looks like I don’t have access anymore.”

That’s the trap. When something you could do yesterday silently stops working, “it must be permissions” is the story your brain reaches for first. It was wrong here — and the way it was wrong is the whole point of this post.

Permissions was the first thing I ruled out

MediaWiki has a tell for this. If you genuinely can’t edit a page, it shows you a read-only “View source” box — no summary field, no “minor edit” checkbox, nothing to submit. She had all of those. The edit form itself was fully live. So she had edit rights; the button simply wasn’t being drawn. That ruled out an entire category of causes in about ten seconds, just by knowing what the actual permission-denied state looks like instead of assuming.

The rabbit hole: blaming PHP

The wiki ran an ancient MediaWiki 1.29 (from 2017), and the host had quietly upgraded the server’s PHP version to 8.2 in the background. Old software choking on a newer PHP runtime is a classic, well-worn failure story, so I chased it first: got hosting access, pinned that site back down to PHP 7.4.

The button was still gone.

That’s when it got interesting — because there was no error anywhere to chase. Clean PHP logs. Clean browser console. Empty Common.js. Nothing crashed. Everything on the page rendered correctly except three specific buttons.

”No error” is a clue, not a comfort

A silent failure that looks like a permissions issue almost always means some code ran, produced nothing, and moved on without complaining about it. So I stopped guessing at platform-level causes and went straight to the source that builds the edit form. One line was the whole bug:

$wgOut->addHTML( "\n", implode( $this->getEditButtons( $tabindex ) ) . "\n" );

addHTML() takes exactly one argument. Someone had written a comma where there should have been a string concatenation . — so the fully-built buttons string silently became a second argument that addHTML() never looked at and quietly discarded. The buttons were being generated perfectly, every time, and then dropped on the floor before they ever reached the page. No crash, no warning, no log line — just three buttons that never existed in the output.

The kicker

Diffing against an older backup of the file showed the original, correct line. Someone had touched this core file during the PHP 8 migration — the original code used a deprecated implode() argument order that PHP 8 actually removed, so it needed a real fix — and while “fixing” that, introduced this typo. The PHP-version story wasn’t wrong, exactly; it’s what caused someone to edit the file. But the bug that shipped wasn’t a PHP compatibility issue at all. It was a one-character mistake wearing a platform problem’s clothes.

One line changed — comma to dot — and the Save button was back.

What I took from it

  • “It looks like a permissions issue” is a hypothesis, not a diagnosis. Check what the software actually shows a user with no permission. It almost always looks different from a bug that merely resembles one, and that check takes seconds.
  • A missing error is information, not an absence of one. If nothing is logging and nothing is crashing, the bug is very likely a silent no-op somewhere in the render path — which means the fix is in the source, not the logs.
  • Keep known-good backups of code you didn’t write yourself. A five-second diff against an old copy of EditPage.php pointed straight at the one changed line and turned a guessing game into a certainty.

Hours of PHP-version archaeology, and the actual fix was deleting one comma. That’s debugging: most of the work is refusing to trust the first plausible story.