{"id":1433,"date":"2026-10-14T18:00:00","date_gmt":"2026-10-14T17:00:00","guid":{"rendered":"https:\/\/wade.one\/blog\/?p=1433"},"modified":"2026-10-14T18:00:00","modified_gmt":"2026-10-14T17:00:00","slug":"an-api-timeout-does-not-mean-the-operation-failed","status":"publish","type":"post","link":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/","title":{"rendered":"An API Timeout Does Not Mean the Operation Failed"},"content":{"rendered":"<p>A timeout tells you that a response did not arrive in time. It does not tell you whether the server finished the operation. That distinction matters whenever a request creates something, sends something or changes a record. Retrying blindly can turn one uncertain result into two very definite mistakes.<\/p>\n<p>AWS explains the problem well in its <a href=\"https:\/\/aws.amazon.com\/builders-library\/making-retries-safe-with-idempotent-APIs\/\">guide to idempotent APIs<\/a>. A caller-provided request identifier lets the service recognise another attempt at the same operation. The identifier needs to belong to the original intent; generating a fresh one for every retry defeats the point.<\/p>\n<p>I would make that behaviour part of the API contract, including what happens if the same key arrives with different parameters or while the original request is still running. Recording the key and performing the change also need a reliable relationship. A separate &#8220;have we seen this?&#8221; check followed by a write is not enough if two workers can both pass the check.<\/p>\n<p>The interface should reflect uncertainty as well. &#8220;We could not confirm the result&#8221; is more honest than &#8220;nothing happened&#8221; when the connection dropped. Give the user a way to check the existing operation before starting another one. A slightly less confident message can save a lot of cleanup.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A timeout tells you that a response did not arrive in time.<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[13],"tags":[257,258,85],"class_list":["post-1433","post","type-post","status-publish","format-standard","hentry","category-programming","tag-apis","tag-idempotency","tag-retries"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>An API Timeout Does Not Mean the Operation Failed - wade.one<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"An API Timeout Does Not Mean the Operation Failed - wade.one\" \/>\n<meta property=\"og:description\" content=\"A timeout tells you that a response did not arrive in time.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/\" \/>\n<meta property=\"og:site_name\" content=\"wade.one\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-14T17:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/Wade-Logo-cropped.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1518\" \/>\n\t<meta property=\"og:image:height\" content=\"1506\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@wadewomersley\" \/>\n<meta name=\"twitter:site\" content=\"@wadewomersley\" \/>\n<meta name=\"twitter:label1\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/10\\\/14\\\/an-api-timeout-does-not-mean-the-operation-failed\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/10\\\/14\\\/an-api-timeout-does-not-mean-the-operation-failed\\\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"An API Timeout Does Not Mean the Operation Failed\",\"datePublished\":\"2026-10-14T17:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/10\\\/14\\\/an-api-timeout-does-not-mean-the-operation-failed\\\/\"},\"wordCount\":213,\"publisher\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#\\\/schema\\\/person\\\/8b4739f8f8bb2cff5d792d4b8779fcc3\"},\"keywords\":[\"apis\",\"idempotency\",\"retries\"],\"articleSection\":[\"Programming\"],\"inLanguage\":\"en-GB\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/10\\\/14\\\/an-api-timeout-does-not-mean-the-operation-failed\\\/\",\"url\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/10\\\/14\\\/an-api-timeout-does-not-mean-the-operation-failed\\\/\",\"name\":\"An API Timeout Does Not Mean the Operation Failed - wade.one\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#website\"},\"datePublished\":\"2026-10-14T17:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/10\\\/14\\\/an-api-timeout-does-not-mean-the-operation-failed\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/10\\\/14\\\/an-api-timeout-does-not-mean-the-operation-failed\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/10\\\/14\\\/an-api-timeout-does-not-mean-the-operation-failed\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/wade.one\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"An API Timeout Does Not Mean the Operation Failed\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/wade.one\\\/blog\\\/\",\"name\":\"wade.one\",\"description\":\"wade womersley - york based software engineer\",\"publisher\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#\\\/schema\\\/person\\\/8b4739f8f8bb2cff5d792d4b8779fcc3\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wade.one\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#\\\/schema\\\/person\\\/8b4739f8f8bb2cff5d792d4b8779fcc3\",\"name\":\"Wade Womersley\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/wp-content\\\/uploads\\\/2015\\\/02\\\/200px.png\",\"url\":\"https:\\\/\\\/wade.one\\\/blog\\\/wp-content\\\/uploads\\\/2015\\\/02\\\/200px.png\",\"contentUrl\":\"https:\\\/\\\/wade.one\\\/blog\\\/wp-content\\\/uploads\\\/2015\\\/02\\\/200px.png\",\"width\":202,\"height\":200,\"caption\":\"Wade Womersley\"},\"logo\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/wp-content\\\/uploads\\\/2015\\\/02\\\/200px.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"An API Timeout Does Not Mean the Operation Failed - wade.one","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/","og_locale":"en_GB","og_type":"article","og_title":"An API Timeout Does Not Mean the Operation Failed - wade.one","og_description":"A timeout tells you that a response did not arrive in time.","og_url":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/","og_site_name":"wade.one","article_published_time":"2026-10-14T17:00:00+00:00","og_image":[{"width":1518,"height":1506,"url":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/Wade-Logo-cropped.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_creator":"@wadewomersley","twitter_site":"@wadewomersley","twitter_misc":{"Estimated reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/#article","isPartOf":{"@id":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/"},"author":{"name":"","@id":""},"headline":"An API Timeout Does Not Mean the Operation Failed","datePublished":"2026-10-14T17:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/"},"wordCount":213,"publisher":{"@id":"https:\/\/wade.one\/blog\/#\/schema\/person\/8b4739f8f8bb2cff5d792d4b8779fcc3"},"keywords":["apis","idempotency","retries"],"articleSection":["Programming"],"inLanguage":"en-GB"},{"@type":"WebPage","@id":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/","url":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/","name":"An API Timeout Does Not Mean the Operation Failed - wade.one","isPartOf":{"@id":"https:\/\/wade.one\/blog\/#website"},"datePublished":"2026-10-14T17:00:00+00:00","breadcrumb":{"@id":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/wade.one\/blog\/2026\/10\/14\/an-api-timeout-does-not-mean-the-operation-failed\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/wade.one\/blog\/"},{"@type":"ListItem","position":2,"name":"An API Timeout Does Not Mean the Operation Failed"}]},{"@type":"WebSite","@id":"https:\/\/wade.one\/blog\/#website","url":"https:\/\/wade.one\/blog\/","name":"wade.one","description":"wade womersley - york based software engineer","publisher":{"@id":"https:\/\/wade.one\/blog\/#\/schema\/person\/8b4739f8f8bb2cff5d792d4b8779fcc3"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wade.one\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":["Person","Organization"],"@id":"https:\/\/wade.one\/blog\/#\/schema\/person\/8b4739f8f8bb2cff5d792d4b8779fcc3","name":"Wade Womersley","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/200px.png","url":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/200px.png","contentUrl":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/200px.png","width":202,"height":200,"caption":"Wade Womersley"},"logo":{"@id":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/200px.png"}}]}},"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":1177,"url":"https:\/\/wade.one\/blog\/2026\/04\/09\/offline-support-sounds-smaller-than-it-is\/","url_meta":{"origin":1433,"position":0},"title":"Offline Support Sounds Smaller Than It Is","author":"","date":"April 9, 2026","format":false,"excerpt":"Offline support looks like a simple feature request until you have to deal with stale data, sync conflicts, retry rules, and user expectations. The hard part is not storing data locally. It is keeping the whole system honest.","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1169,"url":"https:\/\/wade.one\/blog\/2026\/04\/02\/the-problem-with-simple-aws-architectures\/","url_meta":{"origin":1433,"position":1},"title":"The Problem With &#8220;Simple&#8221; AWS Architectures","author":"","date":"April 2, 2026","format":false,"excerpt":"AWS diagrams love to look simple. The problem is that the operational reality behind them is usually doing a lot more work than the picture admits.","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1167,"url":"https:\/\/wade.one\/blog\/2026\/03\/31\/serverless-is-great-until-you-need-to-debug-it-at-2-a-m\/","url_meta":{"origin":1433,"position":2},"title":"Serverless Is Great Until You Need to Debug It at 2 a.m.","author":"","date":"March 31, 2026","format":false,"excerpt":"I still like serverless, but the tradeoff is obvious when something breaks at 2 a.m. The architecture is easy to ship and harder to reason about when you need logs, context, and a fast path to the real failure.","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1168,"url":"https:\/\/wade.one\/blog\/2026\/04\/01\/why-i-still-like-serverless-for-small-teams\/","url_meta":{"origin":1433,"position":3},"title":"Why I Still Like Serverless for Small Teams","author":"","date":"April 1, 2026","format":false,"excerpt":"Serverless has real tradeoffs, but for small teams I still think it usually wins. The operational overhead stays low, the first version ships faster, and the mistakes are easier to afford early on.","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1180,"url":"https:\/\/wade.one\/blog\/2026\/04\/12\/the-hardest-part-of-serverless-is-not-the-code\/","url_meta":{"origin":1433,"position":4},"title":"The Hardest Part of Serverless Is Not the Code","author":"","date":"April 12, 2026","format":false,"excerpt":"The hard part of serverless is usually not writing the handler. It is understanding what failed, what the event looked like, and why the system changed underneath you.","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1172,"url":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/","url_meta":{"origin":1433,"position":5},"title":"What Makes an API Feel Nice to Work With","author":"","date":"April 5, 2026","format":false,"excerpt":"A good API is not just functional. It is predictable, consistent, and easy to use without a lot of guesswork.","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/posts\/1433","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/comments?post=1433"}],"version-history":[{"count":1,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/posts\/1433\/revisions"}],"predecessor-version":[{"id":1454,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/posts\/1433\/revisions\/1454"}],"wp:attachment":[{"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/media?parent=1433"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/categories?post=1433"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/tags?post=1433"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}