Why "active" means nothing to a trigger
getActiveSheet() is a UI concept. It returns whichever tab the user currently has selected in the browser. When you run a function from the Apps Script editor, that user context exists and the call works as expected.
Time-driven triggers, installable onEdit triggers fired by a different user, and doGet/doPost web app handlers all execute in a headless context: no browser, no cursor, no selected tab. In that situation getActiveSheet() does not throw an error. It silently returns the first tab in the spreadsheet, which is whatever sheet happens to be in position 0 — often a cover sheet, a changelog, or something you created years ago.
The first time I hit this, a nightly summary script had been quietly aggregating data from a 'Changelog' tab for two weeks before anyone noticed the numbers were wrong. The script ran clean, no errors, just wrong data. That silence is what makes this bug expensive.