It worked until the hundred and first
Permissions were being read one page at a time. Nobody noticed for a year, because nobody had more than a hundred of them.
A record had a list of permissions attached to it. The code read that list and decided what the user could do. It had been right every single time since it was written.
Then one record had more than a hundred permissions, and it started being quietly wrong.
The default nobody chose
The API returns a hundred items unless you say otherwise. The code did not say otherwise, so it got a hundred, and treated that as the whole list.
That is the part worth sitting with. Nobody decided on a limit of a hundred. Nobody wrote a hundred anywhere. A default was picked by something else, years ago, in a different context, and it silently became a rule in our system.
Why it hid for so long
There was no error. The request succeeded. The list came back. It was just short.
If the list had come back empty, someone would have noticed the first day. Because it came back mostly right, it looked fine, and the missing entries only showed up as someone occasionally not having access to a thing they should have. Which reads as a permissions question, not a pagination bug.
Wrong is easier to find than nearly right.
What I changed
The read now asks for the whole list explicitly. That is the fix, and it is one line.
The habit is the real change. Anywhere I read a list I now ask: what happens when this list is long? Usually one of three things is true, and I have to pick on purpose:
- I want all of it, so say so
- I want a page of it, so handle the rest
- I only want a few, so ask for a few and sort them properly
What I do not want is to take whatever the default hands me and quietly hope the list stays small.
What I keep from it
Bugs that scale with your success are the mean ones. This code was correct while we were small and became wrong as we grew, without changing. Nothing broke on the day it broke.