Skip to content

worlds/vercel.py:204 references vqs_client.DuplicateIdempotencyKeyError, which is not exported by vercel-workers #124

@kalyanaramansanthanam

Description

@kalyanaramansanthanam

Environment

  • vercel==0.5.8
  • vercel-workers==0.0.22
  • Python 3.12 (Vercel Lambda runtime)

The bug

src/vercel/_internal/workflow/worlds/vercel.py:204 catches vqs_client.DuplicateIdempotencyKeyError:

try:
    response = await vqs_client.send_async(...)
    return response["messageId"]
except vqs_client.DuplicateIdempotencyKeyError:
    return f"msg_duplicate_{idempotency_key or 'unknown'}"

But the installed vercel-workers package doesn't expose that name on vercel.workers.client. When the inner send_async raises anything (e.g. BadRequestError from the queue server), Python evaluates the except clause, fails to resolve the attribute, and raises a secondary:

AttributeError: module 'vercel.workers.client' has no attribute 'DuplicateIdempotencyKeyError'

The original exception is lost and the worker handler crashes. Visible in practice whenever world.queue(...) errors at the HTTP layer.

Why CI didn't catch it

Worth flagging as a structural gap:

  1. CI doesn't actually run mypy. [tool.mypy] is configured in pyproject.toml and mypy is in the dev dependency group, but scripts/test.sh is just uv run pytest … — no mypy src/ invocation. The CI job is named "test, including lint and typecheck" but only ruff runs as a lint, and ruff doesn't do cross-module attribute resolution, so undefined vqs_client.<...> access slips through.

  2. Even if mypy ran, the config would silence this specific case. [tool.mypy] ignore_missing_imports = true means mypy treats any module without visible type stubs as Any. vercel-workers appears to be closed-source / not on a public GitHub repo, and likely ships without a py.typed marker visible to vercel-py's CI. So every attribute on vercel.workers.client type-checks as Any silently.

Suggested fix (in priority order)

  1. Reference whatever vercel-workers actually exports for "idempotency key conflict" — possibly a subclass of BadRequestError, or a generic IdempotencyError. If there's no such class, guard the except with getattr(vqs_client, "DuplicateIdempotencyKeyError", _Unreachable) so the worker doesn't AttributeError on unrelated send failures.
  2. Wire mypy src/ into scripts/test.sh and CI, and drop ignore_missing_imports for the vercel.workers.* namespace specifically via [[tool.mypy.overrides]]. (basedpyright is already a dev dep of vercel-workers — the workers maintainers presumably know.) That guards against the next bug of this shape.

Happy to send a PR for either if a maintainer can confirm the intended exception type.

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