{"record":{"id":"68cfeb4e75f65808","repo":"carrierwaveuploader/carrierwave","slug":"need-to-implement-delete-dir-if-you-want-to-use","errorCode":null,"errorMessage":"Need to implement #delete_dir! if you want to use #{self.class.name} as a cache storage.","messagePattern":"Need to implement #delete_dir! if you want to use #(.+?) as a cache storage\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"lib/carrierwave/storage/abstract.rb","lineNumber":35,"sourceCode":"        uploader.deduplicated_filename\n      end\n\n      def store!(file)\n      end\n\n      def retrieve!(identifier)\n      end\n\n      def cache!(new_file)\n        raise NotImplementedError, \"Need to implement #cache! if you want to use #{self.class.name} as a cache storage.\"\n      end\n\n      def retrieve_from_cache!(identifier)\n        raise NotImplementedError, \"Need to implement #retrieve_from_cache! if you want to use #{self.class.name} as a cache storage.\"\n      end\n\n      def delete_dir!(path)\n        raise NotImplementedError, \"Need to implement #delete_dir! if you want to use #{self.class.name} as a cache storage.\"\n      end\n\n      def clean_cache!(seconds)\n        raise NotImplementedError, \"Need to implement #clean_cache! if you want to use #{self.class.name} as a cache storage.\"\n      end\n    end # Abstract\n  end # Storage\nend # CarrierWave\n","sourceCodeStart":17,"sourceCodeEnd":44,"githubUrl":"https://github.com/carrierwaveuploader/carrierwave/blob/b5f0abe10ecf6500309fc83e0e8969cf57ba690e/lib/carrierwave/storage/abstract.rb#L17-L44","documentation":"NotImplementedError raised by the delete_dir! stub on CarrierWave::Storage::Abstract. After a cached file is cleaned up, CarrierWave asks the cache storage to remove the (now empty) per-file cache directory via delete_dir!; engines that never implemented the cache interface fail here, typically right after a successful or failed upload cycle.","triggerScenarios":"Using a store-only storage engine as cache storage (cache_storage unset and storage custom, or cache_storage explicitly set to an engine missing cache methods) so CarrierWave::Uploader::Cache's cleanup path calls cache_storage.delete_dir!(path) on the Abstract stub.","commonSituations":"Same family as the other cache stubs: half-finished custom storages discovered only when cache cleanup runs (often after the first upload in a new environment), fog-as-cache on old versions, or incomplete test doubles.","solutions":["Set config.cache_storage = :file so the file storage handles cache dir lifecycle","Implement #delete_dir!(path) (usually a no-op or recursive rmdir) in your storage subclass","Upgrade CarrierWave when relying on bundled engines like fog for caching"],"exampleFix":"# before\nclass Storage::MyDb < CarrierWave::Storage::Abstract\n  # no cache methods -> delete_dir! NotImplementedError during cleanup\nend\n\n# after\nclass Storage::MyDb < CarrierWave::Storage::Abstract\n  def delete_dir!(path); FileUtils.rm_rf(File.dirname(path)); end\nend","handlingStrategy":"validation","validationCode":"cache_engine = (MyUploader.cache_storage || MyUploader.storage)\nraise \"cache storage must implement #delete_dir!\" unless cache_engine.instance_methods.include?(:delete_dir!)","typeGuard":"def cache_capable_storage?(klass)\n  %i[cache! retrieve_from_cache! delete_dir! clean_cache!].all? { |m| klass.instance_methods.include?(m) }\nend","tryCatchPattern":null,"preventionTips":["Test the full upload lifecycle (cache then cleanup), not just store, for custom engines","Implement delete_dir! even as a deliberate no-op in non-filesystem storages so the Abstract stub never fires"],"tags":["carrierwave","storage","custom-storage","cache","not-implemented"],"backgroundTag":"abstract-method-not-implemented","analyzedSha":"b5f0abe10ecf6500309fc83e0e8969cf57ba690e","analyzedAt":"2026-08-21T18:07:27.715Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}