garrytan/gstack · error · Error
tab-each rejected: subcommand "${innerRaw}" not allowed by y
Error message
tab-each rejected: subcommand "${innerRaw}" not allowed by your token scope (${tokenInfo.scopes.join(', ')}). What it means
Thrown by tab-each when the caller's token does not have the required scope for the inner command. Before fanning out, tab-each canonicalizes the inner command name and runs checkScope(tokenInfo, innerName). Non-root tokens whose scopes do not include the inner command are rejected to prevent a single permission failure from partially mutating tabs — the scope check is done upfront so the whole batch aborts atomically.
Source
Thrown at browse/src/meta-commands.ts:328
// $B tab-each snapshot -i → snapshot every tab
// $B tab-each text → grab clean text from every tab
// $B tab-each goto https://x.y → load the same URL in every tab
if (args.length === 0) {
throw new Error(
'Usage: browse tab-each <command> [args...]\n' +
'Example: browse tab-each snapshot -i'
);
}
const innerRaw = args[0];
const innerName = canonicalizeCommand(innerRaw);
const innerArgs = args.slice(1);
// Scope check the inner command before fanning out, so a single
// permission failure aborts the whole batch instead of partially
// mutating tabs.
if (tokenInfo && tokenInfo.clientId !== 'root' && !checkScope(tokenInfo, innerName)) {
throw new Error(
`tab-each rejected: subcommand "${innerRaw}" not allowed by your token scope (${tokenInfo.scopes.join(', ')}).`
);
}
const tabs = await bm.getTabListWithTitles();
const originalActive = tabs.find(t => t.active)?.id ?? bm.getActiveTabId();
const executeCmd = opts?.executeCommand;
const results: Array<{
tabId: number;
url: string;
title: string;
status: number;
output: string;
}> = [];
try {
for (const tab of tabs) {View on GitHub (pinned to 94993f7401)
Solutions
- Use a token whose scopes include the inner command — check tokenInfo.scopes for the missing permission
- Switch to a root token (clientId === 'root') for operations requiring elevated scope
- Request the additional scope be added to the token by an administrator
Example fix
# before — read-only token trying a write command $B tab-each goto https://example.com # token scope: snapshot,text # after — use a token with goto scope # or use root token
Defensive patterns
Strategy: validation
Validate before calling
// Verify scope before fanning out
const innerName = canonicalizeCommand(args[0]);
if (tokenInfo && tokenInfo.clientId !== 'root' && !checkScope(tokenInfo, innerName)) {
throw new Error(`Token lacks scope for '${innerName}'. Available: ${tokenInfo.scopes.join(', ')}`);
} Type guard
function tokenHasScope(token: TokenInfo, cmd: string): boolean {
return token.clientId === 'root' || checkScope(token, cmd);
} Prevention
- Check tokenInfo.scoes before attempting tab-each with a non-root token
- Use a root token for operations requiring broad permissions
- Request additional scopes from an administrator if needed
When it happens
Trigger: Calling 'browse tab-each <cmd>' with a scoped (non-root) token whose scopes array does not include the canonicalized inner command name.
Common situations: Using a limited-scope API token (e.g., read-only) and trying to fan out a write command like 'goto' or 'click'. Or the token was created with specific scopes that exclude the desired inner command.
Related errors
- Usage: browse tab <id>
- Usage: browse tab-each <command> [args...] Example: browse t
- Chain rejected: subcommand "${c.rawName}" not allowed by you
- Invalid skill name "${name}". Must be lowercase letters/digi
- Invalid file path in stageSkill: "${relPath}".
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/e377e023cd6bc2e5.
Report an issue: GitHub.