RocketChat/Rocket.Chat · error · Error
Invalid command parameter provided, must be a string.
Error message
Invalid command parameter provided, must be a string.
What it means
The authorize step hashes the submitted token with Accounts._hashLoginToken and searches users by services.resume.loginTokens.hashedToken. If no user matches, it responds 401 'Invalid token': the token was forged, truncated, revoked, or expired. Logging out deletes a user's resume tokens, so a token captured before logout becomes invalid immediately.
Solutions
- Log in again and resubmit the consent with the fresh resume token
- Make sure the token comes from the same environment/DB the OAuth server validates against
- Send the complete resume token string (no quotes/whitespace) as access_token or token
- If it persists, verify the user document still contains services.resume.loginTokens entries
Example fix
// before: stale token from an earlier session
body: new URLSearchParams({ allow: 'yes', access_token: oldToken });
// after: fetch a fresh resume token first
const { data } = await (await fetch('/api/v1/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user: 'me', password: '***' }) })).json();
body: new URLSearchParams({ allow: 'yes', access_token: data.authToken }); Defensive patterns
Strategy: validation
Validate before calling
const me = await fetch('/api/v1/me', { headers: { 'X-Auth-Token': token, 'X-User-Id': uid } });
if (!me.ok) { /* token invalid/expired: re-login before calling /oauth/authorize */ } Try / catch
On 401 'Invalid token', discard the stored resume token, re-authenticate, then retry the authorize POST once with the fresh token — more than one retry indicates a deeper session problem.
Prevention
- Validate resume tokens against /api/v1/me before using them in the consent flow
- Never reuse tokens across environments or after logout
- Send the token verbatim (no trimming/encoding beyond URL form rules)
When it happens
Trigger: POST /oauth/authorize with allow=yes and a token that matches no services.resume.loginTokens entry: token from a user who has since logged out; token truncated or mangled in transit; token issued by a different deployment/database (dev vs prod); forged values.
Common situations: Consent submitted after the user logged out elsewhere; DB restored or reset so old tokens no longer exist; multi-replica setups where sessions are not shared; copy-paste errors in manual API testing.
Related errors
- Invalid Api parameter provided, it must be a valid IApi…
- authorization failed when sending push to gateway. not…
- Command does not exist in the system currently
- could-not-access-webdav
- Custom_User_Status_Error_Invalid_User_Status
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/2c8337b54b22a69f.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/app/apps/server/bridges/commands.ts:35
}
protected async doesCommandExist(command: string, appId: string): Promise<boolean> {
this.orch.debugLog(`The App ${appId} is checking if "${command}" command exists.`);
if (typeof command !== 'string' || command.length === 0) {
return false;
}
const cmd = command.toLowerCase();
return typeof slashCommands.commands[cmd] === 'object' || this.disabledCommands.has(cmd);
}
protected async enableCommand(command: string, appId: string): Promise<void> {
this.orch.debugLog(`The App ${appId} is attempting to enable the command: "${command}"`);
if (typeof command !== 'string' || command.trim().length === 0) {
throw new Error('Invalid command parameter provided, must be a string.');
}
const cmd = command.toLowerCase();
if (!this.disabledCommands.has(cmd)) {
throw new Error(`The command is not currently disabled: "${cmd}"`);
}
slashCommands.commands[cmd] = this.disabledCommands.get(cmd) as (typeof slashCommands.commands)[string];
this.disabledCommands.delete(cmd);
void this.orch.getNotifier().commandUpdated(cmd);
}
protected async disableCommand(command: string, appId: string): Promise<void> {
this.orch.debugLog(`The App ${appId} is attempting to disable the command: "${command}"`);
if (typeof command !== 'string' || command.trim().length === 0) {
throw new Error('Invalid command parameter provided, must be a string.');View on GitHub (pinned to b2c16d5842)