{"record":{"id":"65e10d585677c3f1","repo":"danny-avila/LibreChat","slug":"storage-backend-source-does-not-support-file-65e10d","errorCode":null,"errorMessage":"Storage backend \"${source}\" does not support file writes","messagePattern":"Storage backend \"(.+?)\" does not support file writes","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/server/services/Endpoints/agents/skillDeps.js","lineNumber":67,"sourceCode":"\nfunction withDeploymentSkillIds(ids = []) {\n  return mergeDeploymentSkillIds(ids);\n}\n\nfunction getSkillStrategyFunctions(source) {\n  if (isDeploymentSkillFileSource(source)) {\n    return {\n      getDownloadStream: (_req, filepath) => getDeploymentSkillDownloadStream(filepath),\n    };\n  }\n  return getStrategyFunctions(source);\n}\n\nfunction resolveSkillStorage(req, { isImage = false } = {}) {\n  const source = getFileStrategy(req.config, { context: FileContext.skill_file, isImage });\n  const strategy = getStrategyFunctions(source);\n  if (!strategy.saveBuffer) {\n    throw new Error(`Storage backend \"${source}\" does not support file writes`);\n  }\n  return { saveBuffer: strategy.saveBuffer, source };\n}\n\nfunction basename(relativePath) {\n  const slash = relativePath.lastIndexOf('/');\n  return slash === -1 ? relativePath : relativePath.slice(slash + 1);\n}\n\nasync function saveSkillFileContent({ req, skillId, relativePath, content, mimeType }) {\n  const existingFile = await db.getSkillFileByPath(skillId, relativePath);\n  const tenantId = resolveRequestTenantId(req);\n  const fileId = crypto.randomUUID();\n  const filename = basename(relativePath);\n  const storageFileName = `${fileId}__${filename}`;\n  const buffer = Buffer.from(content, 'utf8');\n  const storage = resolveSkillStorage(req, { isImage: mimeType.startsWith('image/') });\n  const filepath = await storage.saveBuffer({","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/services/Endpoints/agents/skillDeps.js#L49-L85","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Configure a writable strategy (local or s3) for the skill_file context.","Implement saveBuffer on any custom strategy used here.","Disable agent skill-file writes if only a read-only deployment source is available.","Verify getStrategyFunctions(source) for the configured source returns saveBuffer."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const strategy = getStrategyFunctions(source);\nif (typeof strategy?.saveBuffer !== 'function') {\n  throw new Error(`Agents storage backend '${source}' cannot write skill files`);\n}","typeGuard":"function strategyCanWrite(strategy) {\n  return strategy != null && typeof strategy.saveBuffer === 'function';\n}","tryCatchPattern":"try { await saveSkillFileContent({ req, skillId, relativePath, content }); }\ncatch (e) { if (/does not support file writes/.test(e.message)) return res.status(400).json({ error: 'Storage backend is read-only' }); throw e; }","preventionTips":["Verify saveBuffer exists at startup for the agents skill context.","Use a writable backend whenever agents can author skill files.","Gate agent skill-write features on a capability check."],"tags":["agents","skills","storage","configuration"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}