carrierwaveuploader/carrierwave · error · CarrierWave::InvalidParameter
invalid filename
Error message
invalid filename
What it means
Raised as CarrierWave::InvalidParameter by Uploader::Cache#original_filename= when the filename portion contains characters matched by CarrierWave::SanitizedFile.sanitize_regexp (/[^[:word:]\.\-+]/) — i.e. anything other than letters, digits, underscore, dot, dash, or plus. This guards the cache path against filenames that could escape or corrupt the cache directory (slashes, '../', spaces, parentheses, null bytes).
Source
Thrown at lib/carrierwave/uploader/cache.rb:209
attr_reader :cache_id
private
def workfile_path(for_file=original_filename)
File.join(CarrierWave.tmp_path, @cache_id, version_name.to_s, for_file)
end
attr_reader :original_filename
def cache_id=(cache_id)
# Earlier version used 3 part cache_id. Thus we should allow for
# the cache_id to have both 3 part and 4 part formats.
raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A(-)?[\d]+\-[\d]+(\-[\d]{4})?\-[\d]{4}\z/
@cache_id = cache_id
end
def original_filename=(filename)
raise CarrierWave::InvalidParameter, "invalid filename" if filename =~ CarrierWave::SanitizedFile.sanitize_regexp
@original_filename = filename
end
def cache_storage
@cache_storage ||= (self.class.cache_storage || self.class.storage).new(self)
end
# We can override the full_original_filename method in other modules
def full_original_filename
forcing_extension(original_filename)
end
end # Cache
end # Uploader
end # CarrierWave
View on GitHub (pinned to b5f0abe10e)
Solutions
- Validate/sanitize the filename before retrieve: filename.gsub(/[^[:word:]\.\-+]/, '_')
- Pass through the untouched uploader-provided cache_name instead of reconstructing it client-side
- Rescue CarrierWave::InvalidParameter and reject the request as malformed
Example fix
# before
cache_name = "#{params[:cache_id]}/#{params[:filename]}"
uploader.retrieve_from_cache!(cache_name) # 'my photo.jpg' -> InvalidParameter
# after
safe_name = params[:filename].to_s.gsub(/[^[:word:]\.\-+]/, '_')
uploader.retrieve_from_cache!("#{params[:cache_id]}/#{safe_name}") Defensive patterns
Strategy: validation
Validate before calling
UNSAFE_FILENAME = /[^[:word:]\.\-+]/
def sanitize_upload_filename(name)
File.basename(name.to_s).gsub(UNSAFE_FILENAME, '_')
end
cache_name = "#{params[:cache_id]}/#{sanitize_upload_filename(params[:filename])}" Type guard
def safe_filename?(name) !name.to_s.match?(CarrierWave::SanitizedFile.sanitize_regexp) end
Try / catch
begin uploader.retrieve_from_cache!(cache_name) rescue CarrierWave::InvalidParameter head :bad_request # treat tampered cache field as malformed input end
Prevention
- Round-trip the exact uploader-provided cache_name; never reconstruct the filename portion from user input
- Strip/replace characters outside [word . - +] in any filename you feed into retrieve_from_cache!
- Treat CarrierWave::InvalidParameter on cache retrieval as hostile input: log and reject, do not retry
When it happens
Trigger: retrieve_from_cache!(cache_name) where the part after the slash contains unsafe characters (e.g. '../evil.php', 'my photo (1).jpg'), or any code assigning uploader.original_filename = with a raw user-supplied name. The normal cache! flow is safe because it wraps files in SanitizedFile which replaces such characters before this setter runs.
Common situations: Tampered hidden cache field replaying a filename with traversal characters; client code rebuilding cache names from user input; middleware or JS upload widgets that re-encode the filename and introduce characters outside the allowed set.
Related errors
- invalid cache id
- Need to implement #cache! if you want to use #{self.class.na
- Need to implement #retrieve_from_cache! if you want to use #
- Need to implement #delete_dir! if you want to use #{self.cla
- Need to implement #clean_cache! if you want to use #{self.cl
AI-assisted analysis of carrierwaveuploader/carrierwave@b5f0abe10e (2026-08-21).
Data as JSON: /api/errors/0f406d39871b4a58.
Report an issue: GitHub.