SillyTavern/SillyTavern · error
Internal Server Error
Error message
Internal Server Error
What it means
Generic 500 returned by the catch block of POST /api/secrets/write when SecretManager.writeSecret throws. writeSecret reads secrets.json, JSON.parses it, deactivates existing entries, pushes the new secret, then atomically rewrites the file via write-file-atomic. Any failure in that chain (corrupted JSON, unreadable/unwritable file, disk full during the atomic temp-file swap) bubbles up here.
Source
Thrown at src/endpoints/secrets.js:525
}
export const router = express.Router();
router.post('/write', (request, response) => {
try {
const { key, value, label } = request.body;
if (!key || typeof value !== 'string') {
return response.status(400).send('Invalid key or value');
}
const manager = new SecretManager(request.user.directories);
const id = manager.writeSecret(key, value, label);
return response.send({ id });
} catch (error) {
console.error('Error writing secret:', error);
return response.sendStatus(500);
}
});
router.post('/read', (request, response) => {
try {
const manager = new SecretManager(request.user.directories);
const state = manager.getSecretState();
return response.send(state);
} catch (error) {
console.error('Error reading secret state:', error);
return response.send({});
}
});
router.post('/view', (request, response) => {
try {
if (!allowKeysExposure) {
console.error('secrets.json could not be viewed unless allowKeysExposure in config.yaml is set to true');View on GitHub (pinned to 8172dcd0ee)
Solutions
- Read the server console output: the line 'Error writing secret:' prints the underlying Error (ENOENT, EACCES, SyntaxError, ENOSPC).
- If SyntaxError: open data/<user>/secrets.json and validate/repair the JSON, or restore from data/<user>/backups/secrets_migration_*.json.
- If EACCES/EROFS: fix ownership/permissions on the user root directory (chmod/chown) or remount the data volume read-write.
- If unrecoverable: back up then delete secrets.json; SecretManager._ensureSecretsFile recreates an empty one on next access.
Example fix
// before: corrupted secrets.json breaks every write
// after: validate and self-heal on startup
import { SecretManager } from './src/endpoints/secrets.js';
try {
new SecretManager(user.directories)._readSecretsFile();
} catch (e) {
fs.copyFileSync(secretsPath, `${secretsPath}.broken-${Date.now()}`);
fs.rmSync(secretsPath, { force: true }); // recreated empty on next write
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before calling /api/secrets/write, sanity-check the target file is parseable
const fs = require('node:fs');
function canWriteSecrets(rootDir) {
const p = require('node:path').join(rootDir, 'secrets.json');
if (!fs.existsSync(p)) return true; // will be auto-created
try { JSON.parse(fs.readFileSync(p, 'utf8')); return true; }
catch { return false; }
} Type guard
/** @param {any} b */
function isValidWriteBody(b) {
return !!b && typeof b === 'object'
&& typeof b.key === 'string' && b.key.length > 0
&& typeof b.value === 'string';
} Try / catch
try {
const r = await fetch('/api/secrets/write', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ key, value, label }) });
if (r.status === 500) throw new Error('secret store unavailable — check secrets.json');
return await r.json();
} catch (e) { showUser('Could not save secret: ' + e.message); } Prevention
- Never hand-edit secrets.json; always use the /write endpoint so the atomic write path runs.
- Run SillyTavern with a dedicated service account that owns data/<user>/.
- Back up data/<user>/secrets.json before upgrades.
- Mount the data directory read-write; never read-only.
When it happens
Trigger: POST /api/secrets/write with a valid key/value but where secrets.json is malformed JSON, where the user's root directory is not writable, where the disk is full, or where an external process (antivirus, indexer) holds an exclusive lock on secrets.json during the atomic write.
Common situations: User hand-edited data/<user>/secrets.json and introduced a syntax error; a partial write from a crashed server left truncated JSON; data directory moved onto a read-only mount; container mounted data volume read-only; Windows Defender locking the file during write.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- AI/ML API key is not set.
- Moonshot AI API key is not set.
- NanoGPT API key is not set.
- Electron Hub API key is not set.
- Chutes API key is not set.
AI-assisted analysis of SillyTavern/SillyTavern@8172dcd0ee (2026-08-13).
Data as JSON: /api/errors/59b5d35aeb3a1a5d.
Report an issue: GitHub.