From f5e95a502cfc91d1a1d44752c19769265e1f0738 Mon Sep 17 00:00:00 2001 From: 9qeklajc Date: Tue, 29 Sep 2026 01:42:13 +0200 Subject: [PATCH] fix: keep the Key not found prefix so routstr SDK purges dead keys --- docs/api/authentication.md | 2 +- docs/api/errors.md | 2 +- routstr/auth.py | 7 ++++++- tests/unit/test_auth_cashu.py | 4 ++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/api/authentication.md b/docs/api/authentication.md index d1926b70..69c7006b 100644 --- a/docs/api/authentication.md +++ b/docs/api/authentication.md @@ -232,7 +232,7 @@ separately as `key_not_found` (also 401) — see { "error": { "type": "invalid_request_error", - "message": "API key not found. Deposit first via /v1/wallet/create to get a key on this node.", + "message": "Key not found. Deposit first via /v1/wallet/create to get a key on this node.", "code": "key_not_found" } } diff --git a/docs/api/errors.md b/docs/api/errors.md index 0c09d7a8..f87e802f 100644 --- a/docs/api/errors.md +++ b/docs/api/errors.md @@ -129,7 +129,7 @@ by key pruning. This is *not* a formatting problem. { "error": { "type": "invalid_request_error", - "message": "API key not found. Deposit first via /v1/wallet/create to get a key on this node.", + "message": "Key not found. Deposit first via /v1/wallet/create to get a key on this node.", "code": "key_not_found" } } diff --git a/routstr/auth.py b/routstr/auth.py index f7b20ccb..bb3f00f8 100644 --- a/routstr/auth.py +++ b/routstr/auth.py @@ -298,11 +298,16 @@ async def _validate_bearer_key_locked( # Falling through to the generic handler below would report it as # "Invalid API key format", sending callers after a formatting bug # that does not exist. Report the real cause instead. + # + # Keep the "Key not found." prefix verbatim: @routstr/sdk (<=0.4.6) + # detects a dead key with a case-sensitive `body.includes("Key not + # found")` probe, and uses it to purge the key from its store. The + # refund path in balance.py already relies on the same prefix. raise HTTPException( status_code=401, detail={ "error": { - "message": "API key not found. Deposit first via /v1/wallet/create to get a key on this node.", + "message": "Key not found. Deposit first via /v1/wallet/create to get a key on this node.", "type": "invalid_request_error", "code": "key_not_found", } diff --git a/tests/unit/test_auth_cashu.py b/tests/unit/test_auth_cashu.py index ea02bb69..ddbdf2a3 100644 --- a/tests/unit/test_auth_cashu.py +++ b/tests/unit/test_auth_cashu.py @@ -350,6 +350,10 @@ async def test_unknown_sk_key_reports_key_not_found(session: AsyncSession) -> No assert detail["error"]["type"] == "invalid_request_error" assert detail["error"]["code"] == "key_not_found" assert "format" not in detail["error"]["message"].lower() + # @routstr/sdk (<=0.4.6) purges a dead key on a case-sensitive + # `body.includes("Key not found")` probe, so the prefix is part of the + # wire contract, not cosmetic. + assert detail["error"]["message"].startswith("Key not found.") @pytest.mark.asyncio