{"record":{"id":"499d065a2cb9f10f","repo":"amruthpillai/reactive-resume","slug":"private-storage-writes-are-not-supported-by-the-lo","errorCode":null,"errorMessage":"Private storage writes are not supported by the local filesystem backend. Configure S3 to store private attachments.","messagePattern":"Private storage writes are not supported by the local filesystem backend\\. Configure S3 to store private attachments\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/api/src/features/storage/service.ts","lineNumber":142,"sourceCode":"\t\tconst fullPath = this.resolvePath(prefix);\n\n\t\ttry {\n\t\t\tconst files = await fs.readdir(fullPath, { recursive: true });\n\n\t\t\treturn files.map((file) => join(prefix, file));\n\t\t} catch (error: unknown) {\n\t\t\t// If directory doesn't exist, return empty array\n\t\t\tif (error && typeof error === \"object\" && \"code\" in error && error.code === \"ENOENT\") {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync write({ key, data, private: isPrivate }: StorageWriteInput): Promise<void> {\n\t\tif (isPrivate) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Private storage writes are not supported by the local filesystem backend. Configure S3 to store private attachments.\",\n\t\t\t);\n\t\t}\n\n\t\tconst fullPath = this.resolvePath(key);\n\n\t\tawait fs.mkdir(dirname(fullPath), { recursive: true });\n\t\tawait fs.writeFile(fullPath, data);\n\t}\n\n\tasync read(key: string): Promise<StorageReadResult | null> {\n\t\tconst fullPath = this.resolvePath(key);\n\t\ttry {\n\t\t\tconst [arrayBuffer, stats] = await Promise.all([fs.readFile(fullPath), fs.stat(fullPath)]);\n\n\t\t\treturn {\n\t\t\t\tdata: arrayBuffer,\n\t\t\t\tsize: stats.size,","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/packages/api/src/features/storage/service.ts#L124-L160","documentation":"LocalStorageService.write throws a plain Error when called with private:true. The local filesystem backend has no access-control boundary, so private attachments (e.g. application documents) cannot be stored safely. The message tells operators to configure S3. Unlike the oRPC errors above, this is a generic Error — it will surface as HTTP 500 unless wrapped.","triggerScenarios":"Any code path that requests a private write (StorageWriteInput.private = true) while S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY / S3_BUCKET are unset, so getStorageService() returned the LocalStorageService. Most commonly: uploading an application/cover-letter attachment marked private.","commonSituations":"Local/dev deployments that omitted S3/SeaweedFS config but enabled features requiring private attachments; a feature flag turning on private uploads without provisioning S3; CI without SeaweedFS running a flow that uploads private docs.","solutions":["Configure S3-compatible storage: set S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_BUCKET (and optionally S3_ENDPOINT/REGION/FORCE_PATH_STYLE), or start the seaweedfs compose service.","If S3 is unavailable in your environment, disable the feature that requests private writes rather than allowing the write to be attempted.","Gate the private-write code path on a capability check (e.g. storage.getCapabilities().supportsPrivate) and degrade gracefully.","Confirm getStorageService() actually selects S3 after the env change by hitting the storage healthcheck endpoint."],"exampleFix":"// before: unconditional private write\nawait storage.write({ key, data, contentType: 'application/pdf', private: true });\n// after: guard on backend capability\nif (!storage.supportsPrivateWrites()) {\n  return c.json({ error: 'Private attachments require S3 storage.' }, 501);\n}\nawait storage.write({ key, data, contentType: 'application/pdf', private: true });","handlingStrategy":"validation","validationCode":"function supportsPrivateWrites(): boolean {\n  return Boolean(env.S3_ACCESS_KEY_ID && env.S3_SECRET_ACCESS_KEY && env.S3_BUCKET);\n}\nif (isPrivate && !supportsPrivateWrites()) throw new ConfigError('Configure S3 for private attachments.');","typeGuard":"function isPrivateWriteInput(i: StorageWriteInput): i is StorageWriteInput & { private: true } {\n  return i.private === true;\n}","tryCatchPattern":"try { await storage.write({ key, data, contentType, private: true }); }\ncatch (e) {\n  if (/local filesystem backend/.test(String((e as Error).message))) { /* degrade: disable feature or use S3 */ }\n  throw e;\n}","preventionTips":["Provision S3/SeaweedFS before enabling private-attachment features.","Gate private writes on a backend capability check.","Add a startup healthcheck that fails fast if private features are on without S3."],"tags":["storage","configuration","s3","filesystem","attachments"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}