Skip to content

[Hackathon] Malformed API key (autocorrected dash / smart quote / newline) surfaces as opaque UNAVAILABLE after wasted retries #89

Description

@Davidson3556

Discord Username / User ID

Davidson

What does this improvement do?

Add a client-side guard so a malformed API key fails fast with a clear VALIDATION_ERROR (exit 5) instead of an opaque, misleading UNAVAILABLE (exit 10) emitted only after the full retry-and-backoff cycle.

The CLI sends the key as the x-api-key HTTP header. If the key contains a character that is invalid in an HTTP header value — most commonly an autocorrected dash (en/em-dash, codepoint > 255), a smart quote, an emoji, or an embedded newline — Node's fetch throws TypeError: Cannot convert argument to a ByteString ... deep in the transport layer. That throw is classified as a network error and retried with exponential backoff, then surfaced as a generic "service temporarily unavailable" — even though retrying can never succeed and the real problem is the key.

These artifacts are exactly what you get when a key is copy-pasted from a doc, email, or chat where autocorrect silently rewrote a hyphen to an en-dash.

Details / implementation notes

Reproduction (key contains a copy-paste en-dash, codepoint 8211):

$ export TESTSPRITE_API_KEY="sk-user-abc–def"
$ testsprite project list --output json
{
  "error": {
    "code": "UNAVAILABLE",
    "message": "Cannot convert argument to a ByteString because the character at index 11 has a value of 8211 which is greater than 255.",
    "nextAction": "Service is temporarily unavailable. The CLI retries with exponential backoff; if this persists, report it.",
    "details": {}
  }
}
# exit 10 — and it took ~2s because of the wasted retry backoff

The operator is told the service is down and to wait for retries; in reality their key will never work until they re-copy it.

Proposed fix — mirror the existing hardening guards:

  • The merged assertValidEndpointUrl guard (fix(cli): reject a malformed --endpoint-url with a clear VALIDATION_ERROR #19) already validates the resolved endpoint before the client is built and returns a typed VALIDATION_ERROR.
  • assertValidApiKey already exists in spirit as assertIdempotencyKey (validates an outgoing header value is printable ASCII before fetch can throw a ByteString error).

Add an assertValidApiKey(key) that rejects any character outside printable ASCII (0x20–0x7E) and call it:

  1. In makeHttpClient (client-factory.ts), right after the authRequired check — so the runtime path (env TESTSPRITE_API_KEY or credentials file) fails fast with a clear message naming the likely cause.
  2. In runConfigure (auth.ts), before the /me verification ping — so setup never wastes retries and never reports the key as "rejected by " when the server never received it.

Message names the usual culprit (an autocorrected dash / smart quote) so the fix is obvious.

I have a PR ready for this.

Confirmations

  • I have searched existing issues and this is not a duplicate.
  • I have provided my Discord identity above for reward coordination.

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