Status code misleads
Read error.code, not the status code
A wrong model name comes back as 503. A missing messages field comes back as 500. Both are permanent mistakes in your request — no amount of retrying fixes either — but openai-python, openai-node and the Anthropic SDKs all retry 408, 409, 429 and every 5xx twice by default, with exponential backoff. So one typo becomes three round trips and tens of seconds of waiting before the real reason surfaces. The body always carries the real reason in error.code; the status code is the part that lies.