Summary

  • OpenAI opened an API incident at 00:55:27 UTC on 29 July after elevated errors appeared with the invalid_prompt code.
  • The company said it had applied a mitigation at 01:39:33 and marked all impacted services recovered at 02:20:19, a public timeline of 1:24:52.
  • The incident record does not state what HTTP status accompanied invalid_prompt; separately, OpenAI’s Python SDK maps an actual HTTP 400 to BadRequestError and excludes an ordinary 400 from its default retry set.
  • A customer system that permanently rejects every invalid_prompt response can therefore misclassify a provider incident as a payload defect and leave valid work unrecovered.
  • OpenAI disclosed no root cause, failure rate, geography, affected model or endpoint list, request count or customer denominator; not every such error in the interval can be attributed to the incident.

An API error does two jobs at once. It reports that an operation failed, and it suggests who should act next. A timeout asks the caller to wait or retry. A rate limit asks it to slow down. An invalid prompt normally asks the developer to repair the input.

OpenAI’s 29 July incident broke that neat division. The status page itself named elevated invalid_prompt errors as a provider incident affecting APIs. For an operator, the important fact is not merely that requests failed. It is that the failure vocabulary pointed toward the customer while the incident response sat with the supplier.

That mismatch can be more damaging than an unmistakable server error. If the response is a 500, it often enters a retry queue and an incident dashboard. If it is a 400, it commonly enters a dead-letter queue, a user-facing validation message or a permanent-failure counter. OpenAI has not said which status this incident returned, so retaining the actual transport status is part of the control rather than a fact to infer from the code name.

The SDK’s taxonomy reinforces the first diagnosis

OpenAI’s official Python client maps an HTTP 400 response to BadRequestError. That is a sensible default: most 400 responses do indicate a request the server will not accept without change. The client separately classifies authentication, permission, not-found, conflict, validation, rate-limit and server failures.

Its retry policy follows the same logic. The documentation says connection errors, 408 timeouts, 409 conflicts, 429 rate limits and responses at or above 500 receive two automatic retries by default. The implementation also honours explicit x-should-retry guidance before applying those status rules. An ordinary 400 falls through to “do not retry”.

Nothing in this incident makes that general policy wrong. Automatically replaying every malformed request would waste capacity, hide application defects and sometimes multiply side effects. The lesson is narrower: a status code and exception class are evidence, not an infallible allocation of responsibility.

Corroboration must not become blind retry

A resilient client needs a second classification layer. When a sudden cluster of previously valid request shapes begins returning the same nominally permanent error, the system can compare the time series with the provider’s official incident feed. If the provider confirms a matching service event, the client may move affected operations from “invalid forever” to “quarantined pending controlled replay”.

That is not permission to hammer the API. The queue should be bounded, back off, respect any provider instruction and distinguish operations safe to repeat from those that might already have taken effect. A test request or synthetic probe can establish whether the path is healthy before a backlog is released.

The decision must also preserve genuine input validation. Some requests during the interval may really have been malformed. A provider incident and customer mistakes can coexist. Replaying the same bad payload indefinitely would convert careful incident handling into noise.

Request IDs are the bridge between two views of the failure

The Python SDK exposes a request ID on failed APIStatusError exceptions. That identifier lets a customer point the supplier toward a specific transaction without relying only on a local timestamp or an error string. During a classification incident, retaining it is more valuable than flattening every failure into invalid_prompt.

Operators should also retain the endpoint, model, status, error code, SDK version, attempt number and a privacy-safe fingerprint of the request shape. The fingerprint can show that a known-good payload pattern suddenly failed without placing raw prompts, secrets or personal data in an incident log.

This creates two parallel records. The customer record answers what was sent, what came back and whether replay occurred. The provider record answers when a public incident was opened, mitigated and resolved. Neither replaces the other, but their timestamps can reveal when an apparently local validation problem became correlated service failure.

“Resolved” closes the banner, not the customer queue

OpenAI’s structured status record places investigation at 00:55:27 UTC, mitigation and monitoring at 01:39:33, and resolution at 02:20:19. The status page lists APIs as the affected component and labels the impact minor.

Those facts do not describe every customer’s downtime. OpenAI warns that its availability metrics are aggregated across tiers, models and error types, and individual experience may vary. The record supplies no denominator from which to calculate how many requests or organisations were affected.

Resolution means OpenAI considered the listed service recovered. It does not mean a customer’s discarded jobs returned, a dead-letter queue emptied or a user resubmitted work. Recovery therefore requires reconciliation: identify failures inside the incident interval, exclude genuine validation defects, replay eligible work once, and verify the resulting state.

The missing post-incident facts still matter

OpenAI has not disclosed the root cause or explained why the incident surfaced as invalid_prompt. It has not stated the accompanying HTTP status, named affected models or endpoints, published an error-rate curve, identified geography, or quantified requests and customers. Without those facts, it would be wrong to claim that all same-named errors—or all 400 responses—in the interval came from one provider fault.

The public evidence nevertheless supports a concrete operational conclusion. Error taxonomies are contracts between suppliers and customer automation. When a provider incident crosses that contract, the safest response is neither permanent rejection nor indiscriminate retry. It is a third state: corroborated uncertainty, with preserved evidence, bounded replay and an explicit reconciliation step after recovery.

The next useful disclosure would explain the cause of the misclassification and whether OpenAI changed the service or its error semantics. Until then, teams can improve their own control plane. They can make “who appears to be at fault” a revisable diagnosis rather than a property permanently encoded in one error name.

Sources