Skip to content

feat: better error messages around permissions, QOL improvements & better webhook replay options#61

Merged
dylanjha merged 8 commits intomainfrom
feat/permission-guards
Mar 21, 2026
Merged

feat: better error messages around permissions, QOL improvements & better webhook replay options#61
dylanjha merged 8 commits intomainfrom
feat/permission-guards

Conversation

@dylanjha
Copy link
Copy Markdown
Contributor

@dylanjha dylanjha commented Mar 20, 2026

  • If you hit a 404 we will show this error now:
Error: Permission denied or this route does not exist.
{"error":{"type":"not_found","messages":["The requested resource either doesn't exist or you don't have access to it."]}}

Your token "data-read" has permissions: data:read

You can create a new token at:
https://dashboard.mux.com/settings/access-tokens
Then run 'mux login' to authenticate with the new token.
  • better handling of webhook event replays
  • it's no longer an option to replay --all (we have no limits on how
    many events are stored, so that's insane)
  • you can say webhooks events replay <event-id> OR
  • webhooks events replay --count 10 which will replay the last 10
    events in chronological order

other fixes

  • the package.json version committed in the repo, to avoid confusion is 0.0.0 (prev was incorrectly 1.0.0) -- the real version gets set at build/publish time and tagged with a git tag
  • update notice does not show when the version is exactly 0.0.0 (b/c that's a dev build)
  • Print out update notice on errors too (prev we only did this on successful commands)
  • Improve update notifier -- on every command check the local cache to see if we're current (no network request). If the cache is stale, then spin off a bg task to refresh it async. If it's updated then it will get picked up on the next run. (this is what codex does, and I think it's the best approach)

Note

Medium Risk
Touches error handling paths across many CLI commands and changes update-notice behavior at process exit, which could affect user output/exit timing and messaging if misclassified errors occur.

Overview
Centralizes CLI error handling by introducing src/lib/errors.ts and switching most commands to call handleCommandError, including special-casing AuthenticationError and treating NotFoundError as potentially missing permissions (fetching /whoami to print token scopes and next steps).

Improves webhook tooling by changing webhooks events replay from --all to --count <n> (replaying the last N events via new getRecentEvents), while keeping single-event replay by ID; webhooks listen now detects permission failures via checkFetchPermissionError and exits immediately instead of retrying.

Refines update notices and versioning: repo package.json version is set to 0.0.0; checkForUpdate becomes cache-only (skipped for 0.0.0) and a new refreshUpdateCache updates cache in the background; src/index.ts prints the update notice on process exit so it appears even when commands error.

Written by Cursor Bugbot for commit 5a230d8. This will update automatically on new commits. Configure here.

If you hit a 404 we will show this error now:

```
Error: Permission denied or this route does not exist

Your token "{TOKEN_NAME}" has permissions: data:read

You can create a new token at:
https://dashboard.mux.com/settings/access-tokens
Then run 'mux login' to authenticate with the new token.
```

Note this detail:

As far as I can tell all 404s are all basically "Insufficient Privileges"

- /assets/:wrong_id will return 400 for *any* value of :wrong_id

```
❯ ./dist/mux assets get "HoGN5KDgq5hEdA98v33cWolrMCvSCLejgLBqI4yiA7k"
Error: 401 {"error":{"type":"invalid_parameters","messages":["Invalid external asset ID, mismatching environment"]}}
```

If you somehow truly hit a nonexistant route:

- GET /nonexistant-route
- GET /assets/:id (but your token doesn't have permissions)

Both of these return:

```
Error: 404 {"error":{"type":"not_found","messages":["The requested resource either doesn't exist or you don't have access to it."]}}
```

But with the CLI, it would be fairly hard (impossible?) to hit a "true"
404

So for all intents & purposes, we'll presume the 404 is a permission
issue and tell you what permissions the current token has and how you
can create a new one.
Comment thread src/commands/webhooks/listen.ts Outdated
Comment thread src/commands/webhooks/listen.ts
Comment thread src/lib/errors.ts
- hardcode 0.0.0 in dev package.json
- (real version gets published based on GH tag)
- surpress the update avail check in dev based on the exact 0.0.0
  version
Comment thread src/lib/errors.ts
- no longer an option to replay --all (we have no limits on how
many events are stored, so that's insane)
- you can say `webhooks events replay <event-id>` OR
- `webhooks events replay --count 10` which will replay the last 10
  events in chronological order
@dylanjha dylanjha changed the title feat: better error messages around permissions feat: better error messages around permissions, QOL improvements & better webhook replay options Mar 20, 2026
Comment thread src/index.ts
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

lastChecked: Date.now(),
firstSeenAt,
}).catch(() => {}); // best-effort
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Background cache refresh ignores CI/dev environment guards

Medium Severity

refreshUpdateCache makes a network request to npm on every invocation without checking for CI, MUX_NO_UPDATE_CHECK, version 0.0.0, or non-TTY environments. The old checkForUpdate had all these guards before doing any network I/O. Now that the architecture splits "check" and "refresh", the guards only exist in checkForUpdate but not refreshUpdateCache. In ephemeral CI environments (no persistent cache), every command invocation triggers a fetch with up to a 3-second timeout that blocks process exit, even though the update notice will never be shown.

Additional Locations (1)
Fix in Cursor Fix in Web

@dylanjha dylanjha merged commit 695991c into main Mar 21, 2026
8 checks passed
@dylanjha dylanjha deleted the feat/permission-guards branch March 21, 2026 05:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants