SillyTavern/SillyTavern · warning
Forbidden: No permission to list branches of global extensio
Error message
Forbidden: No permission to list branches of global extensions.
What it means
The /branches endpoint (extensions.js:229-231) checks admin privileges when the request body has global set to truthy. Non-admin users cannot list branches of extensions in the global directory. This is the same authorization pattern used by /install and /update.
Source
Thrown at src/endpoints/extensions.js:231
return response.status(500).send('Internal Server Error. Check the server logs for more details.');
}
});
router.post('/branches', async (request, response) => {
try {
if (typeof request.body.extensionName !== 'string') {
return response.status(400).send('Bad Request: A valid extensionName is required in the request body.');
}
const { extensionName, global } = request.body;
const extensionNameSanitized = sanitize(extensionName);
if (!extensionNameSanitized) {
return response.status(400).send('Bad Request: A valid extensionName is required in the request body.');
}
if (global && !request.user.profile.admin) {
console.error(`User ${request.user.profile.handle} does not have permission to list branches of global extensions.`);
return response.status(403).send('Forbidden: No permission to list branches of global extensions.');
}
const basePath = global ? PUBLIC_DIRECTORIES.globalExtensions : request.user.directories.extensions;
const extensionPath = path.join(basePath, extensionNameSanitized);
if (!fs.existsSync(extensionPath)) {
return response.status(404).send(`Directory does not exist at ${extensionPath}`);
}
const git = simpleGit({ baseDir: extensionPath, ...OPTIONS });
// Unshallow the repository if it is shallow
const isShallow = await git.revparse(['--is-shallow-repository']) === 'true';
if (isShallow) {
console.info(`Unshallowing the repository at ${extensionPath}`);
await git.fetch('origin', ['--unshallow']);
}
// Fetch all branchesView on GitHub (pinned to 8172dcd0ee)
Solutions
- Remove the global field (or set it to false) for user-scoped branch listing.
- If global branch listing is needed, have an admin perform the request.
Example fix
// before — non-admin trying global branches
fetch('/api/extensions/branches', {
method: 'POST',
body: JSON.stringify({ extensionName: 'my-ext', global: true }),
});
// after — user-scoped
fetch('/api/extensions/branches', {
method: 'POST',
body: JSON.stringify({ extensionName: 'my-ext' }),
}); Defensive patterns
Strategy: validation
Validate before calling
// Only set global when the user is an admin.
function buildBranchesPayload(extensionName, isAdmin, globalRequested) {
const payload = { extensionName };
if (globalRequested && isAdmin) {
payload.global = true;
} else if (globalRequested && !isAdmin) {
console.warn('User is not admin — falling back to user-scoped branch listing.');
}
return payload;
}
const payload = buildBranchesPayload(name, user.profile.admin, wantGlobal);
await fetch('/api/extensions/branches', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
}); Type guard
/** Checks whether the current user may list branches of global extensions. */
function canListGlobalBranches(user) {
return Boolean(user?.profile?.admin === true);
} Prevention
- Default to user-scoped branch listing by omitting the global field.
- Only send global: true when the user is confirmed as admin.
- Handle 403 by falling back to user-scoped or prompting admin login.
When it happens
Trigger: POST /api/extensions/branches with { extensionName: "...", global: true } (or any truthy value) when request.user.profile.admin is falsy.
Common situations: Non-admin user has global: true set inadvertently; frontend bug sends the flag; or the user misunderstands their privilege level.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Forbidden: No permission to install global extensions.
- Forbidden: No permission to update global extensions.
- Forbidden: No permission to delete global extensions.
- Forbidden: No permission to switch branches of global extens
- Forbidden: No permission to move extensions.
AI-assisted analysis of SillyTavern/SillyTavern@8172dcd0ee (2026-08-13).
Data as JSON: /api/errors/87a6b08152a19d18.
Report an issue: GitHub.