Skip to content

[P2][errors] error.code is set to the whole human message for {status:"fail", data:{error:"<sentence>"}} responses #145

Closed

Description

@karlwaldman

Status

Confirmed live on 2026-09-13 against production, with origin/main 4bd2900 code plus the #101 branch. The defect is in error_from_response, which is unchanged on main.

Defect

oilpriceapi/exceptions.py error_from_response:

code_value = _first_value(sources, "code", "error_code", "type")
if code_value is None and isinstance(nested_data_error, str):
    code_value = nested_data_error

When the API answers with the render_fail envelope, data.error is a human sentence, not a machine code. The SDK copies that sentence into error.code and error.machine_code. Anything that branches or aggregates on error.code sees a unique free-text string per request, for example one that embeds the requested slug.

Repro

import os
from oilpriceapi import OilPriceAPI
from oilpriceapi.exceptions import DataNotFoundError

with OilPriceAPI(api_key=os.environ["OILPRICEAPI_KEY"], max_retries=1) as client:
    try:
        client.request("GET", "/v1/fuel-surcharge/nope/latest")
    except DataNotFoundError as error:
        print(repr(error.code))

Output on 2026-09-13:

code: "Unknown carrier 'nope'. Covered carriers: odfl, saia, estes, xpo, abf, tforce, averitt, southeastern-freight."
message: "Unknown carrier 'nope'. Covered carriers: odfl, saia, estes, xpo, abf, tforce, averitt, southeastern-freight."

Wire body: {"status":"fail","data":{"error":"Unknown carrier 'nope'. ...","covered_carriers":[...],"hint":"..."}}.

Every V1::FuelSurchargeController 400/404 uses this shape, and so do other render_fail callers in the API.

Expected

When data.error is a sentence rather than a code-shaped token, leave error.code as None (or derive a stable code from the status). Keep the sentence in message. A narrow fix: only fall back to data.error when it matches something like ^[A-Z][A-Z0-9_]*$.

Before changing this, check tests/unit/test_error_contract.py for any pinned legacy fixture that relies on the fallback.

Activity

  1. added a commit that references this issue on Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions