danny-avila/LibreChat · error · Error

Storage backend "${source}" does not support file writes

Error message

Storage backend "${source}" does not support file writes

What it means

Thrown by resolveSkillStorage in the agents skill dependencies module when the resolved skill_file strategy lacks a saveBuffer function. Identical in intent to the skills-route variant: the active storage backend must support buffer writes for the agents feature to save skill files.

Source

Thrown at api/server/services/Endpoints/agents/skillDeps.js:67

function withDeploymentSkillIds(ids = []) {
  return mergeDeploymentSkillIds(ids);
}

function getSkillStrategyFunctions(source) {
  if (isDeploymentSkillFileSource(source)) {
    return {
      getDownloadStream: (_req, filepath) => getDeploymentSkillDownloadStream(filepath),
    };
  }
  return getStrategyFunctions(source);
}

function resolveSkillStorage(req, { isImage = false } = {}) {
  const source = getFileStrategy(req.config, { context: FileContext.skill_file, isImage });
  const strategy = getStrategyFunctions(source);
  if (!strategy.saveBuffer) {
    throw new Error(`Storage backend "${source}" does not support file writes`);
  }
  return { saveBuffer: strategy.saveBuffer, source };
}

function basename(relativePath) {
  const slash = relativePath.lastIndexOf('/');
  return slash === -1 ? relativePath : relativePath.slice(slash + 1);
}

async function saveSkillFileContent({ req, skillId, relativePath, content, mimeType }) {
  const existingFile = await db.getSkillFileByPath(skillId, relativePath);
  const tenantId = resolveRequestTenantId(req);
  const fileId = crypto.randomUUID();
  const filename = basename(relativePath);
  const storageFileName = `${fileId}__${filename}`;
  const buffer = Buffer.from(content, 'utf8');
  const storage = resolveSkillStorage(req, { isImage: mimeType.startsWith('image/') });
  const filepath = await storage.saveBuffer({

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Configure a writable strategy (local or s3) for the skill_file context.
  2. Implement saveBuffer on any custom strategy used here.
  3. Disable agent skill-file writes if only a read-only deployment source is available.
  4. Verify getStrategyFunctions(source) for the configured source returns saveBuffer.
Defensive patterns

Strategy: validation

Validate before calling

const strategy = getStrategyFunctions(source);
if (typeof strategy?.saveBuffer !== 'function') {
  throw new Error(`Agents storage backend '${source}' cannot write skill files`);
}

Type guard

function strategyCanWrite(strategy) {
  return strategy != null && typeof strategy.saveBuffer === 'function';
}

Try / catch

try { await saveSkillFileContent({ req, skillId, relativePath, content }); }
catch (e) { if (/does not support file writes/.test(e.message)) return res.status(400).json({ error: 'Storage backend is read-only' }); throw e; }

Prevention

When it happens

Trigger: The file strategy for the skill_file context returns a strategy (possibly the deployment-skill read-only source fallback) that does not implement saveBuffer, and an agent skill file write is attempted.

Common situations: Deployment-mode skill file source active in an environment where agents attempt writes; a custom strategy without saveBuffer; misconfigured FILE_STRATEGY for the agents context.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/65e10d585677c3f1. Report an issue: GitHub.