{"record":{"id":"6262d6db9f81eaf7","repo":"nocobase/nocobase","slug":"file-manager-no-linked-or-default-storage-provid","errorCode":null,"errorMessage":"[file-manager] no linked or default storage provided","messagePattern":"\\[file-manager\\] no linked or default storage provided","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/@nocobase/plugin-file-manager/src/server/server.ts","lineNumber":200,"sourceCode":"    const data = await this.uploadFile({ storageName: name, subPath, filePath });\n    return await collectionRepository.create({ values: { ...data, ...values }, transaction });\n  }\n\n  parseStorage(instance) {\n    return this.app.environment.renderJsonTemplate(instance.toJSON());\n  }\n\n  async uploadFile(options: UploadFileOptions) {\n    const { storageName, subPath, filePath, documentRoot } = options;\n\n    if (!this.storagesCache.size) {\n      await this.loadStorages();\n    }\n    const storages = Array.from(this.storagesCache.values());\n    const cachedStorage = storages.find((item) => item.name === storageName) || storages.find((item) => item.default);\n\n    if (!cachedStorage) {\n      throw new Error('[file-manager] no linked or default storage provided');\n    }\n\n    const storage = {\n      ...cachedStorage,\n      options: { ...(cachedStorage.options || {}) },\n      path: resolveStoragePath(cachedStorage.path, subPath),\n    };\n\n    const fileStream = fs.createReadStream(filePath);\n\n    if (documentRoot) {\n      storage.options['documentRoot'] = documentRoot;\n    }\n\n    const StorageType = this.storageTypes.get(storage.type);\n    const storageInstance = new StorageType(storage);\n\n    if (!storageInstance) {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/plugins/@nocobase/plugin-file-manager/src/server/server.ts#L182-L218","documentation":"uploadFile needs a storage configuration to write the file to. It looks up the storages cache by storageName; if none matches, it falls back to the storage flagged as default. If neither exists, no destination is defined, so it throws. This typically happens before any file bytes are written.","triggerScenarios":"Calling uploadFile({ storageName: 'xxx', filePath, ... }) where 'xxx' is not in the storages cache AND no storage has default: true; or not passing storageName at all (or a file record/collection without a linked storage) when there is no default storage configured.","commonSituations":"Fresh install where the default storage record was never created or was disabled; storage name typo; storages cache stale — storage added in another instance without a reload; a file collection's storage option points to a deleted storage.","solutions":["Mark one storage configuration as default in the file-manager storage settings (or pass an existing storageName explicitly).","Pass a storageName that matches an existing, enabled storage record exactly.","Ensure the storage collection record exists and loadStorages has run (restarting the app reloads the cache).","Fix the collection's storage option to reference an existing storage name."],"exampleFix":"// before\nawait app.pm.get('file-manager').uploadFile({ storageName: 'local-backup', filePath }); // not configured\n// after: use the actual storage name or configure default\nawait app.pm.get('file-manager').uploadFile({ storageName: 'local', filePath });","handlingStrategy":"validation","validationCode":"const storages = Array.from(fileManager.storagesCache.values());\nconst ok = (storageName && storages.some(s => s.name === storageName)) || storages.some(s => s.default);\nif (!ok) throw new Error('Configure a default storage or pass a valid storageName');","typeGuard":"const hasUsableStorage = (fm: any, name?: string): boolean =>\n  !!Array.from(fm.storagesCache.values()).find((s: any) => s.name === name || s.default);","tryCatchPattern":"try {\n  await fileManager.uploadFile(opts);\n} catch (err) {\n  if (err.message.includes('no linked or default storage provided')) {\n    // configure a default storage and retry once after loadStorages()\n    await fileManager.loadStorages();\n  } else { throw err; }\n}","preventionTips":["Always keep exactly one default storage configured in each app.","Pass an explicit storageName for non-default destinations.","After creating/deleting storages, ensure loadStorages is triggered on all instances.","Check that file collections' storage option points to an existing storage."],"tags":["file-manager","storage","configuration"],"backgroundTag":"missing-storage-configuration","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}