From cf127e16e84d65de2587ddf47298bf83ecf43696 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Sun, 26 Jul 2026 00:16:51 -0700 Subject: [PATCH] fix(management): stop emitting a dead docs link in problem documents The RFC 9457 `type` was `https://docs.litellm.ai/errors/`, copied from the standard's own error example. That path is a 404 and there is no docs section behind it, so every error body shipped a broken link RFC 9457 only requires `type` to identify the problem type; it encourages, but does not require, that dereferencing it yield documentation. An https URI makes a promise we are not keeping, so use `urn:litellm:error:` instead, which carries the same machine-readable identity with nothing to resolve. Switching to an https base later is a contract change for anyone matching on `type`, so that should wait for pages that actually exist A test pins the identifier against regressing to an https docs URL, since the existing assertion built the expected value from the same constant and would have stayed green whatever it held --- .../management_endpoints/management_v1/common.py | 5 ++++- .../management_v1/test_spend_logs.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/management_endpoints/management_v1/common.py b/litellm/proxy/management_endpoints/management_v1/common.py index f4b6ad1ac11..c0e7f49f2e9 100644 --- a/litellm/proxy/management_endpoints/management_v1/common.py +++ b/litellm/proxy/management_endpoints/management_v1/common.py @@ -13,7 +13,10 @@ from litellm.types.proxy.management_endpoints.management_v1 import ( MANAGEMENT_V1_PREFIX = "/management/v1" PROBLEM_CONTENT_TYPE = "application/problem+json" -PROBLEM_TYPE_BASE = "https://docs.litellm.ai/errors/" +# A URN, not an https URL: RFC 9457 only asks that `type` identify the problem +# type, and an https URI promises documentation at that address. Switch to an +# https base only when pages actually exist to serve. +PROBLEM_TYPE_BASE = "urn:litellm:error:" class ManagementProblem(Exception): diff --git a/tests/test_litellm/proxy/management_endpoints/management_v1/test_spend_logs.py b/tests/test_litellm/proxy/management_endpoints/management_v1/test_spend_logs.py index e6eb3d25a38..79f13a6f703 100644 --- a/tests/test_litellm/proxy/management_endpoints/management_v1/test_spend_logs.py +++ b/tests/test_litellm/proxy/management_endpoints/management_v1/test_spend_logs.py @@ -224,6 +224,19 @@ def test_rejects_a_malformed_window_as_a_problem_document(mock_prisma_client, as assert "error" not in body +def test_problem_type_is_an_identifier_not_a_dead_docs_link(mock_prisma_client, as_proxy_admin): + """RFC 9457 only asks that `type` identify the problem type. An https URI promises + human-readable documentation at that address, and https://docs.litellm.ai/errors/ + is a 404, so emitting one would ship a broken link in every error body.""" + _mock_rows(mock_prisma_client, []) + + problem_type = _get("filter[startTime][gte]=yesterday&filter[startTime][lte]=2026-07-24T00:00:00Z").json()["type"] + + assert problem_type.startswith("urn:") + assert "docs.litellm.ai" not in problem_type + assert not problem_type.startswith("http") + + def test_rejects_an_unknown_query_parameter(mock_prisma_client, as_proxy_admin): """A silently ignored filter over-returns data, which is worse than a rejected request.""" query_raw = _mock_rows(mock_prisma_client, [])