Skip to content

v0.4.3: 'no keyset with ID' on V1-format keyset (16 hex chars) from registered Nutshell 0.20.0 mint #497

@gvilleg

Description

@gvilleg

Summary

routstr-core v0.4.3 (0.4.3+g7fd0cdf, ghcr.io/routstr/core:latest) fails to validate a Cashu V3 cashuA token from a Nutshell 0.20.0 mint with the error:

{
  "error": {
    "message": "CASHU token processing failed: no keyset with ID: 0049550c03fb517f",
    "type": "cashu_error",
    "code": 400
  }
}

The mint is registered as the only allowed mint (CASHU_MINTS=https://mint.refreshpoolpro.com), the mint is healthy, the keyset 0049550c03fb517f is the active V1-format keyset published by the mint, and the proofs in the token reference exactly that keyset ID. Yet routstr reports it doesn't know the keyset.

Environment

  • routstr-core: v0.4.3 (commit g7fd0cdf), image ghcr.io/routstr/core:latest, fresh DB (no carryover state)
  • Mint: Nutshell 0.20.0, public URL https://mint.refreshpoolpro.com
  • Mint backend: LNbits → LND v0.19.3-beta
  • Token: V3 cashuA, 3 sats, two proofs, generated via Nutshell CLI 0.20.0 with --legacy flag

Mint metadata

GET https://mint.refreshpoolpro.com/v1/info:

{
  "name": "Refresh Pool Mint",
  "pubkey": "022be1e90eac4014ec0dac3e93328d1ab665c0abf871bfe1a56f362fe2649c607c",
  "version": "Nutshell/0.20.0",
  "description": "Private Cashu mint on Lightning",
  "urls": ["https://mint.refreshpoolpro.com"],
  "nuts": ["NUT-07", "NUT-08", "NUT-09"]
}

GET https://mint.refreshpoolpro.com/v1/keysets:

{
  "keysets": [
    {
      "id": "0049550c03fb517f",
      "unit": "sat",
      "active": true,
      "input_fee_ppk": 100
    }
  ]
}

GET https://mint.refreshpoolpro.com/v1/keys returns the active keyset with 64 denomination keys for 0049550c03fb517f.

Routstr config

CASHU_MINTS=https://mint.refreshpoolpro.com

GET http://routstr/v1/info correctly reports:

{
  "mints": ["https://mint.refreshpoolpro.com"]
}

So the mint URL is registered. But the keyset is not.

Reproduction

  1. Configure routstr-core v0.4.3 with CASHU_MINTS=https://mint.refreshpoolpro.com only.
  2. Mint a small V3 cashuA token from the same mint via any wallet that emits TokenV3 (Nutshell CLI cashu send 3 --legacy).
  3. POST a chat completion request with the token in X-Cashu header:
T='cashuAeyJ0b2tlbi...' # V3 cashuA token, 3 sats, mint=https://mint.refreshpoolpro.com
curl -sm30 -XPOST http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "X-Cashu: $T" \
  -d '{"model":"qwen3-32b","messages":[{"role":"user","content":"hi"}],"max_tokens":5}'

Observed

{
  "error": {
    "message": "CASHU token processing failed: no keyset with ID: 0049550c03fb517f",
    "type": "cashu_error",
    "code": 400
  }
}

Token is not spent (proofs remain valid in the wallet — re-receivable).

Expected

routstr should fetch the keyset from the registered mint when it encounters an unknown keyset ID for an allowed mint URL. The mint's /v1/keys endpoint exposes the keyset for free, no auth needed. After fetching, proof validation should proceed normally.

Notable

  • The keyset ID 0049550c03fb517f is 16 hex characters = V1 keyset format. Newer Cashu wallets may emit V2-format keyset IDs (66 hex chars from a 33-byte pubkey). routstr-core may have a parsing constraint that only handles V2 IDs, treating V1 IDs as unknown even though the mint reports them.
  • Empty-proofs cashuA tokens ({"proofs":[],"mint":"..."}) do pass through routstr cleanly and return Insufficient balance — meaning the mint URL is recognized at one layer but the keyset registration/lookup at the proof-validation layer fails.
  • V4 cashuB tokens (the default emitted by cashu.me) fail at an even earlier layer with "Invalid authentication token format", before the keyset check is reached. That may be a separate sub-bug; happy to file separately if useful.

History

This bug was first encountered on 2026-05-05 against routstr-core 0.4.0 with the same mint. v0.4.3's release notes (refund handling, x-cashu flow, multi-mint swaps, fee handling, model routing) did not appear to touch this code path. Re-verified today (2026-05-09) on a fresh deployment with wiped DB and the canonical ghcr.io/routstr/core:latest image — same error.

Workaround

None on the routstr side. Forced to fall back to L402 / Aperture / direct LND payment paths until this is fixed.

What would help me move forward

Either:

  1. Confirmation that V1 keyset IDs (16 hex chars) are intentionally unsupported, in which case operators with older Nutshell deployments need to know to upgrade keysets, OR
  2. A pointer to where keyset registration/lookup happens in the codebase so I can submit a fix for V1 ID handling.

Happy to provide additional logs, full token, or test directly against any patched build.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions