SillyTavern/SillyTavern · warning
User not found
Error message
User not found
What it means
Returned as HTTP 404 by POST /api/users/change-avatar when storage.getItem(toKey(handle)) returns a falsy value (users-private.js:79). This means no user record exists under that handle in node-persist. The handler passed the handle/authorization/URL checks but the target account is not present in storage.
Source
Thrown at src/endpoints/users-private.js:81
}
if (request.body.handle !== request.user.profile.handle && !request.user.profile.admin) {
console.error('Change avatar failed: Unauthorized');
return response.status(403).json({ error: 'Unauthorized' });
}
// Avatar is not a data URL or not an empty string
if (!request.body.avatar.startsWith('data:image/') && request.body.avatar !== '') {
console.warn('Change avatar failed: Invalid data URL');
return response.status(400).json({ error: 'Invalid data URL' });
}
/** @type {import('../users.js').User} */
const user = await storage.getItem(toKey(request.body.handle));
if (!user) {
console.error('Change avatar failed: User not found');
return response.status(404).json({ error: 'User not found' });
}
await storage.setItem(toAvatarKey(request.body.handle), request.body.avatar);
return response.sendStatus(204);
} catch (error) {
console.error(error);
return response.sendStatus(500);
}
});
router.post('/change-password', async (request, response) => {
try {
if (!request.body.handle) {
console.warn('Change password failed: Missing required fields');
return response.status(400).json({ error: 'Missing required fields' });
}
View on GitHub (pinned to 8172dcd0ee)
Solutions
- Verify the handle exists by calling GET /api/users/get (admin) and matching exactly.
- Use the exact handle string returned by /me or /get, preserving case.
- If the user was deleted, refresh the user list in the UI before allowing avatar changes.
Example fix
// before
body: JSON.stringify({ handle: 'SomeUser', avatar: dataUrl })
// after — fetch the canonical handle first
const users = await fetch('/api/users/get').then(r => r.json());
const match = users.find(u => u.name === 'SomeUser');
if (!match) throw new Error('user not found');
body: JSON.stringify({ handle: match.handle, avatar: dataUrl }) Defensive patterns
Strategy: validation
Validate before calling
async function ensureUserExists(handle) {
const users = await fetch('/api/users/get', { method:'POST' }).then(r => r.json());
if (!users.some(u => u.handle === handle)) throw new Error('handle not found: ' + handle);
} Try / catch
const res = await fetch('/api/users/change-avatar', { ... });
if (res.status === 404) { showUserNotFoundError(); return; } Prevention
- Use the exact handle string returned by /me or /get (case-sensitive).
- Refresh the user list after create/delete operations.
- Do not confuse display 'name' with 'handle'.
When it happens
Trigger: The handle was deleted, never created, or was passed with different casing/whitespace than how it is stored (the key uses toKey(handle) without normalization on this route, unlike /create which slugifies).
Common situations: Client cached a stale handle after the user was deleted; a typo in the handle; case mismatch (storage keys are case-sensitive); the user exists only in the default fallback and not as a stored record.
Related errors
- Not Found
- Directory does not exist at ${extensionPath}
- Folder '${folderId}' not found.
- User not found
- Missing required fields
AI-assisted analysis of SillyTavern/SillyTavern@8172dcd0ee (2026-08-13).
Data as JSON: /api/errors/c2b1fd28cefea092.
Report an issue: GitHub.