Learning from Production Incidents

Learning from production incidents is the feedback loop that turns a failure seen by real users into a lasting improvement. An incident is an unplanned event in production that harms users or the business: an outage, wrong data, a payment taken twice. After the service is restored, the team reviews the incident in a postmortem, finds which tests or checks should have caught the problem, and adds them, usually as regression tests.

Example: some customers were charged twice after a release. The fix stops the double charges; the learning is asking why no test ever ran against a slow payment provider, then adding one that does.

Why it matters

A production incident is the most expensive way to find a defect: users are harmed, support and finance spend time on it, and the team works under pressure. If the only outcome is a hotfix, the conditions that let the defect escape stay in place, and a similar incident follows.

For a tester, every incident is evidence about the test approach that no review can provide: it shows exactly where the test basis, test levels, environments or oracles did not match reality. Using that evidence without blame keeps the regression suite tied to real risks rather than guesses.

From incident to prevention: the feedback loop

This lesson starts where detection ends. The order matters: restore the service first, investigate second, and change tests and process last, once the facts are known.

In ISTQB terms, what users experience in an incident is a failure: the system does not do what it is required to do. The cause may be a code defect, but also configuration, data, capacity or a third-party service, so establish what failed and why before deciding that a fix and a new test are the answer.

  • Detect and declare: an alert, a synthetic check or a customer report opens an incident record with time, impact and owner.
  • Mitigate: stop the harm with a rollback, a feature flag or a configuration change. Mitigation buys time; it is not the fix.
  • Reconstruct the timeline: deployments, configuration changes, alerts, logs and decisions, all in one time zone.
  • Hold a blameless postmortem: impact, timeline, contributing causes and action items.
  • Analyse the test gap: which test, check or review could have caught it, at which level, and why it did not.
  • Prevent and verify: add regression tests and other actions, each with an owner and a due date, and confirm they are done.
From incident to prevention: detect, mitigate, rebuild the timeline, hold a blameless postmortem, find the test gap, then add regression tests and other owned actions and verify them.
  1. 1Detect and declaretime, impact, ownerAn alert, a synthetic check or a customer report opens the incident record
  2. 2Mitigatenot yet the fixA rollback, a feature flag or a configuration change stops the harmservice first
  3. 3Reconstruct the timelineDeployments, configuration changes, alerts, logs and decisions, in one time zone
  4. 4Blameless postmortemimpact, timeline, causes, action itemsContributing causes in the system and the process, not a person to punish
  5. 5Test gap analysisWhich test or check could have caught it, at which level, and why it did nottester leads
  6. 6Regression tests and other actionsTests, requirement, environment, monitoring: each with an owner and a due date
  7. 7VerifyThe new test fails on the faulty version and passes on the fix; every action is closed

Throughout steps 3–5 Blameless: ask what and why, not who

Then:Into the regression suite and the risk analysis for the next release

Blameless postmortems

The lesson on quality culture introduced the postmortem as a written record of an incident: its impact, detection, mitigation, causes and follow-up actions. Here you run one. The Google SRE book recommends agreeing the triggers in advance, for example user-visible downtime or degradation beyond a threshold, any data loss, a manual intervention such as a rollback, a long resolution time, or a failure that monitoring did not detect.

Blameless means the review looks for contributing causes in the system and the process, not for a person to punish, and assumes everyone acted in good faith with the information they had. This is practical, not polite: people who fear blame leave out details, and the review misses the real causes. Blameless does not mean unaccountable; every action item has a named owner.

  • Blaming: "The developer forgot the timeout case." Blameless: "The retry path had no test, and the code review checklist has nothing on slow responses."
  • Blaming: "QA missed it." Blameless: "The payment mock in the test environment always answers in under a second, so the timeout path never ran."
  • "Human error" is never a root cause on its own: ask what made the error easy to make and hard to notice.

From postmortem to test gaps and regression tests

The tester's main contribution to a postmortem is the test gap analysis. Trace the failure back through the test process: was there a requirement, a test condition and a test case for this behaviour, and did the test run against this build in an environment like production? Each "no" marks a gap, and one incident often has several. Each kind of gap calls for a different action.

  • Missing test condition or test case: neither the requirement nor the risk analysis named the situation, or the test design never reached it, for example no boundary values at the edge. Add the condition, the acceptance criterion or the test case.
  • Wrong test level: only an end-to-end happy-path test existed; a unit or API test reaches the faulty branch more easily.
  • Unrealistic data or environment: test data, mocks, time zone, configuration or volumes differ from production.
  • Weak oracle: the test ran but did not assert what went wrong, for example it checked the HTTP status but not the number of charges.
  • Test not run: skipped, quarantined as flaky, or left out of the regression selection for this change.
  • Detection gap: users found the problem before monitoring did. That action belongs to monitoring, not to the test suite.

Try it: Regression Scenario Generator Try it: Test Case Generator

Worked example: a double charge after a release

A fictional incident in an online store. Release 7.3 lowered the payment client's timeout from 30 to 10 seconds. Under load the provider sometimes answered after more than 10 seconds; the client then retried with a new payment reference, which the provider treated as a new payment, so some customers were charged twice.

In the postmortem excerpt below, customers rather than monitoring detected the problem, 67 minutes after the first duplicate charge, and most action items are tests and checks, not the code fix.

  • Once the incident was declared, mitigation took twenty minutes; prevention needed a requirement, two tests, a new test-environment capability and an alert.
  • Before the fix, the API test was run against release 7.3 and failed with two charges; with the fix it passed. A regression test that has never failed against the defect proves nothing about it.
  • The tests target the condition, a slow provider followed by a retry, not the exact orders from the incident, so they also protect every other flow that uses the same payment client.
INC-0412  Customers charged twice for one order after release 7.3 (fictional)

Impact     37 orders charged twice; all refunded the same day; no data lost
Timeline   all times UTC+3
  09:40  Release 7.3 deployed: payment client timeout 30 s -> 10 s
  09:58  First duplicate charge (found later in the payment logs)
  11:05  First customer complaint to support
  11:30  Incident declared; payments team and QA join
  11:50  Mitigated: timeout back to 30 s by configuration; no new duplicates
  15:00  All duplicate charges refunded
Detection  by customers, 67 minutes after the first duplicate; no alert fired

Contributing causes (no individuals named)
  - A retry after a timeout sends a new payment reference, so the provider
    cannot recognise it as the same payment.
  - The payment requirement said nothing about retries.
  - The payment mock in every test environment answers in under 1 s,
    so the timeout-and-retry path never ran in any test.
  - No monitoring signal for "more than one successful charge per order".

Action items                                                      owner  due
  1  Acceptance criterion: a retried payment never charges twice  PO     7.4
  2  Unit test: a retry reuses the original payment reference     dev    7.4
  3  API test: the mock answers the first call after 12 s, the
     retry at once; exactly one charge, order status PAID         QA     7.4
  4  Payment mock simulates slow answers and, like the provider,
     treats a repeated payment reference as the same payment      QA     7.4
  5  Alert on any order with more than one successful charge      ops    7.4

Try it: Timestamp Converter Try it: Date Difference Calculator

Common mistakes

  • Writing the postmortem around a person ("the developer forgot") instead of the conditions that made the error possible.
  • Adding a regression test that replays the customer's exact order instead of the condition behind the failure.
  • Never running the new test against the faulty version, so nobody knows whether it would have caught the incident.
  • Putting every new check into a slow end-to-end UI test when a unit or API test reaches the faulty branch faster.
  • Treating "add more tests" as the only action when the gap is in the requirement, the environment or the monitoring.
  • Leaving action items without an owner and a due date, so they are never done.

The QA perspective

The tester usually joins after mitigation but can prepare at once: which tests ran against the release, where, and with which data. In the postmortem, ask the gap questions calmly and include the test process; "our tests could not see this because the mock never times out" is a finding about the system, not a confession.

Afterwards, link the incident, the defect, the new test cases and the changed requirement in the tracker, and check at the next release that the action items are closed. Review escaped defects every few months: repeated gaps of one kind, such as time zones or retries, feed the risk analysis and the test strategy.

Practice exercise

Turn a flash-sale time-zone incident into tests

Your task

Incident (fictional): a flash sale was announced to run until the end of 30 September, Riyadh time (UTC+3). The server compared the end time with the current time in UTC, so the sale price stayed on three hours too long, until 02:59:59 on 1 October in Riyadh. Finance noticed the next morning. All automated tests run on CI machines set to UTC, and the sale tests used dates a day before and a day after the end.

The draft postmortem says: "The developer forgot to convert to Riyadh time." and "QA should have tested it." Rewrite both sentences blamelessly, classify the test gaps, design the regression tests and name at least one action that is not a test.

Steps
  1. Rewrite the two blaming sentences as statements about the system and the process.
  2. Classify the test gaps using the categories from this lesson.
  3. Design at least two regression tests with the level, the exact input times and the expected results.
  4. Add the actions that are not tests, and say how you will prove that the new tests detect the defect.
Show the model answer
Model answer

Blameless rewrites: "The sale-end check compared an end time meant in Riyadh time with the server clock in UTC; no requirement or checklist names the time zone for sale dates." and "The sale tests used dates a full day from the end, and all tests run in UTC, so the three-hour gap could not appear."

Test gaps: missing test condition, because the requirement does not state the time zone; missing test case, because no boundary values were tested around the moment the sale ends; unrealistic environment, because every test runs in UTC; detection gap, because finance, not monitoring, found the problem.

Regression tests: a unit test with a fixed clock (the test sets the current time instead of reading the real one), where 30 September 20:59:59 UTC (23:59:59 in Riyadh) gets the sale price and 21:00:00 UTC (midnight in Riyadh) gets the regular price; an API test that sets the test environment's clock to 30 September 21:00:00 UTC, prices the product and expects the regular price; and one more run of the suite with the machine time zone set to Asia/Riyadh, whose results must match the UTC run, which shows they do not depend on the server's zone.

Other actions: state the time zone in the sale requirement, alert on orders charged a sale price after the sale's end time, and check other date rules, such as coupons and delivery cut-offs, for the same pattern. Prove the tests by running them against the faulty version, where 21:00:00 UTC still gets the sale price and they fail, then against the fix, where they pass.

Frequently asked questions

Does every incident need a full postmortem?

No. Agree the criteria in advance, such as user-visible impact beyond a threshold, any data loss, a rollback or other manual intervention, a long resolution time, or a problem that monitoring did not detect. Smaller incidents can get a short written review, but several similar small incidents together deserve a full postmortem.

Does blameless mean nobody is responsible?

No. Nobody is punished for an honest mistake made with the information they had, but every action item has a named owner and a due date, and the team is accountable for finishing them. The absence of blame is what lets people describe their decisions honestly, and the analysis depends on that.

Must every incident end with a new automated test?

An incident caused by a defect should normally get at least one regression test at the lowest level that can detect it. When the cause is capacity, a third-party outage or a configuration change, the better action may be an alert, a configuration check or a release checklist item. Record the decision either way.

How does a postmortem relate to root cause analysis?

Root cause analysis, such as the 5 whys or a fishbone diagram described in the defect triage guide, is a technique used inside a postmortem to get from the failure to its causes. The postmortem is wider: it also records impact, timeline, detection and mitigation, it usually finds several contributing causes rather than a single one, and it ends with owned actions.

References

Practise with Mutqan tools

Generate structured test cases (id, title, preconditions, steps, expected result, priority) from a feature description and field list.

Test Design

Convert a date and time between timezones (Riyadh, Amman, Delhi, UTC, New York, London…).

Utilities

Convert timestamps (seconds, milliseconds, microseconds) to human dates and back, in any timezone.

Utilities

Calculate the exact difference between two dates in years, months, days, hours and total units.

Utilities

Go deeper

Your progress on this topic

Part of the QA Roadmap