{"record":{"id":"df3d453bb4304aff","repo":"carrierwaveuploader/carrierwave","slug":"need-to-implement-cache-if-you-want-to-use-sel","errorCode":null,"errorMessage":"Need to implement #cache! if you want to use #{self.class.name} as a cache storage.","messagePattern":"Need to implement #cache! if you want to use #(.+?) as a cache storage\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"lib/carrierwave/storage/abstract.rb","lineNumber":27,"sourceCode":"\n      attr_reader :uploader\n\n      def initialize(uploader)\n        @uploader = uploader\n      end\n\n      def identifier\n        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":9,"sourceCodeEnd":44,"githubUrl":"https://github.com/carrierwaveuploader/carrierwave/blob/b5f0abe10ecf6500309fc83e0e8969cf57ba690e/lib/carrierwave/storage/abstract.rb#L9-L44","documentation":"NotImplementedError raised by the cache! stub on CarrierWave::Storage::Abstract. Any storage engine whose class does not override cache! (the base class only provides empty store!/retrieve! bodies) blows up the moment CarrierWave tries to write a cache file through it. Cache storage is resolved as self.class.cache_storage || self.class.storage, so a store-only engine used as cache storage hits this on every upload.","triggerScenarios":"Setting config.cache_storage (or storage, with cache_storage unset) to a custom engine that subclasses CarrierWave::Storage::Abstract but only implements store!/retrieve!, or using a store-only engine where CarrierWave then calls cache_storage.cache!(file) inside Uploader::Cache#cache!.","commonSituations":"Writing a custom database/S3-compatible storage and forgetting the cache half; on versions where :fog does not implement cache methods, config.storage = :fog without config.cache_storage = :file; test doubles standing in for storage.","solutions":["Set config.cache_storage = :file so uploads cache on local disk and only final storage uses your engine","Implement #cache! (alongside retrieve_from_cache!, delete_dir!, clean_cache!) in your CarrierWave::Storage::Abstract subclass","If using fog and hitting this, upgrade CarrierWave — its Fog storage implements the cache interface"],"exampleFix":"# before\nclass Storage::MyDb < CarrierWave::Storage::Abstract\n  def store!(file); ...; end\nend\nCarrierWave.configure { |c| c.storage = :my_db } # cache! NotImplementedError on upload\n\n# after\nCarrierWave.configure do |c|\n  c.storage = :my_db\n  c.cache_storage = :file # cache locally, store remotely\nend","handlingStrategy":"validation","validationCode":"# fail fast at boot instead of on first upload\ncache_engine = (MyUploader.cache_storage || MyUploader.storage)\nunless cache_engine.instance_methods.include?(:cache!)\n  raise \"#{cache_engine} cannot be used as cache storage: implement #cache!\"\nend","typeGuard":"# for custom storage classes\ndef cache_capable_storage?(klass)\n  klass.instance_methods.include?(:cache!) &&\n    klass.instance_methods.include?(:retrieve_from_cache!) &&\n    klass.instance_methods.include?(:delete_dir!) &&\n    klass.instance_methods.include?(:clean_cache!)\nend","tryCatchPattern":null,"preventionTips":["Default to config.cache_storage = :file whenever the main storage is custom or remote","Cover all four cache interface methods (#cache!, #retrieve_from_cache!, #delete_dir!, #clean_cache!) in custom storages and their specs","Boot-time assert the resolved cache storage responds to the full cache interface"],"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"}