The printer said Success and deleted a director
Until today, the onboarding and offboarding tracker from last week’s post only made tasks and nagged people about them. Today it started doing things. Three new workflows went in:
- create a new starter’s Microsoft 365 account,
- cut off a leaver’s access on their last day,
- add or remove people in the scan-to-email address book on the office’s two Kyocera printers.
By the evening, three things had told me something worked when it hadn’t: SharePoint, a printer, and my own workflow. The printer did it while deleting a director.
The poll that could never fire
Cutting off a leaver is the dangerous one. It disables a real account, so it got the most care. It only acts on a person chosen through the directory’s person picker. A short never-touch list (the directors, IT, the admin account) can’t be disabled whatever a record says. And it isn’t triggered by a button in a list, where a stray click could lock someone out mid-shift. Someone ticks “Revoke access requested” on the leaver’s record, and the workflow polls for that.
The poll filtered on:
fields/RevokeAccessRequested eq true
SharePoint’s Yes/No columns filter as 1 and 0. eq true isn’t an error.
It’s accepted, it returns 200, and it matches nothing, ever.
So the workflow was armed, active, green on every check, and structurally incapable of firing. Two earlier checks of mine had passed against it, because an empty result is exactly what you’d expect on a day nobody is leaving. Only running it against a record I knew was ticked showed the problem.
A quiet poll and a broken poll look identical. Before you trust one, prove it can find something.
A printer with no API
Kyocera doesn’t publish an API for the address book. The printer’s own web admin page manages it, so the automation sends the same form posts that page does, worked out by reading the page’s JavaScript. A firmware update can change all of that without notice. I took that risk on knowingly.
One finding along the way: with device authentication switched off, as it was here, anyone on the office network can read or rewrite those address books. If you run these printers, turn it on. It’s with the client now as a separate security item.
Then the printer started lying.
The success page
The delete form has a row of fields that look exactly like where the entry ids should go. They aren’t; the real admin page never fills them in. Put the ids there and the printer returns HTTP 200 and its success page, and deletes nothing.
Same shape as the Yes/No filter, on completely different hardware: a healthy response to a request that did nothing.
Two small numbers
Each address book entry carries two small integers: the address number shown in the list, and an internal id. The delete wants the address number.
During the build, one entry’s internal id went into a delete. It happened to match the address number of someone else entirely, a director, and the printer deleted him instead. Then it showed the success page.
He was back within four minutes, but it’s the one I keep thinking about. Deletes now never trust a number handed to them. They look the person up by exact name on a fresh read of the address book, refuse if they find nobody or more than one match, and read the book again afterwards to prove the entry is gone.
A failure that read as “not there”
The workflow’s web request was set never to raise an error, so a failed read of the address book came back as empty data. Empty meant “this person isn’t in the book”, so it added them, and on the retry it added them again. One new starter briefly appeared twice.
A failed read has to stop the work. It must never be quietly treated as an answer.
The one I got wrong out loud
Reads from the printer need two request headers, a cookie and a referrer, and they need both. Either one alone gets a 500 error.
My Python test script happened to send both, so it always worked. curl and n8n sent neither, so they always failed. The failures lined up with a burst of heavy testing, so I read it as the printers falling over under load. I restarted two production printers and told the client that’s what had happened.
It wasn’t. Testing each header on its own reproduced the failure and proved nothing. Only testing them together found it. When you’re working out which headers a request needs, test the combination, not just each one alone.
The record is also a claim
Every task the automation finishes gets an evidence note saying what it did. One run wrote “Added to the printer address book” for someone who was on neither printer. The loop had come back empty for them, and the note was built from whatever came back.
A false “done” is worse than a failure, because nobody retries something marked done. The note now refuses to write unless every printer reported a real outcome, and it says what actually happened (“already present”, “nothing to remove”) rather than what was asked for.
The typo the picker caught
The first real leaver went through later that day. The name typed on their record read “Dominquez”, with a q. The account, and the printer entry, were “Dominguez”, with a g. Anything matching on the typed name would have found nobody and reported “not present”. The person picker resolved the right account.
Where it landed
Five real starters and leavers went through the printer workflow end to end, and every outcome was checked by reading both address books directly, not by trusting the workflow’s own report. The entry counts moved exactly as they should: one printer from 18 to 20, the other from 29 to 28. Re-running one person found them already on both printers and changed nothing.
And because every one of these failures was quiet, a watchdog went in the same day. It checks every workflow every five minutes and raises an alert if one goes silent, because a stopped workflow throws no error. It just looks like there’s nothing to do.
The rule I’m keeping from today: a success response tells you the request was accepted. It never tells you anything changed. Act, then read it back.