{"record":{"id":"4b46597665a891a0","repo":"instructure/canvas-lms","slug":"destination-dest-path-already-exists","errorCode":null,"errorMessage":"Destination '#{dest_path}' already exists","messagePattern":"Destination '#(.+?)' already exists","errorType":"exception","errorClass":"CanvasUnzip::DestinationFileExists","httpStatus":null,"severity":"warning","filePath":"gems/canvas_unzip/lib/canvas_unzip.rb","lineNumber":216,"sourceCode":"\n    def size\n      case type\n      when :zip\n        entry.size\n      when :tar\n        entry.header.size\n      end\n    end\n\n    # yields byte count\n    def extract(dest_path, overwrite: false, maximum_size: DEFAULT_BYTE_LIMIT)\n      dir = directory? ? dest_path : File.dirname(dest_path)\n      FileUtils.mkdir_p(dir)\n      return unless file?\n\n      raise SizeLimitExceeded if size > maximum_size\n      if File.exist?(dest_path) && !overwrite\n        raise DestinationFileExists, \"Destination '#{dest_path}' already exists\"\n      end\n\n      digest = Digest::SHA2.new(512)\n      ::File.open(dest_path, \"wb\") do |os|\n        case type\n        when :zip\n          entry.get_input_stream do |is|\n            entry.set_extra_attributes_on_path(dest_path)\n            buf = +\"\"\n            while (buf = is.sysread(::Zip::Decompressor::CHUNK_SIZE, buf))\n              os << buf\n              digest.update(buf)\n              yield(buf.size) if block_given?\n            end\n          end\n        when :tar\n          while (buf = entry.read(BUFFER_SIZE))\n            os << buf","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/canvas_unzip/lib/canvas_unzip.rb#L198-L234","documentation":"CanvasUnzip::Entry#extract raises DestinationFileExists with this message when writing an archive entry to dest_path that already exists on disk and overwrite was not set to true. It protects against silently clobbering existing files during extraction.","triggerScenarios":"Extracting an archive into a destination folder that already contains a file with the same name, without overwrite: true; extracting the same archive twice; entry names colliding after path sanitization (e.g. two entries normalizing to the same dest path).","commonSituations":"Re-running an import/extraction job that failed halfway (partial files left behind); extracting user uploads into a shared directory with fixed names; case-insensitive filesystems making 'A.txt' collide with 'a.txt'.","solutions":["Pass overwrite: true to extract if replacing existing files is intended (e.g. entry.extract(dest, overwrite: true)).","Extract into a fresh, unique temp directory (Dir.mktmpdir) per archive and move results afterwards.","Delete or clear the destination before re-running a previously failed extraction.","Detect collisions up front by checking File.exist? for each entry and renaming or skipping as appropriate.","Rescue CanvasUnzip::DestinationFileExists to handle per-file collisions gracefully in streaming mode."],"exampleFix":"// before\nentry.extract(dest_path) # raises if dest_path exists\n// after\nentry.extract(dest_path, overwrite: true)\n# or\nentry.extract(dest_path) unless File.exist?(dest_path)","handlingStrategy":"try-catch","validationCode":"raise FileExists, dest_path if File.exist?(dest_path) && !overwrite","typeGuard":"def extraction_target_free?(dest_path)\n  !File.exist?(dest_path)\nend","tryCatchPattern":"begin\n  entry.extract(dest_path)\nrescue CanvasUnzip::DestinationFileExists\n  entry.extract(dest_path, overwrite: true) if overwrite?\nend","preventionTips":["Extract into a fresh Dir.mktmpdir per archive","Clean partial results after failed extractions","Pass overwrite: true when replacement is intended","Watch for name collisions on case-insensitive filesystems"],"tags":["file","file-exists","overwrite","zip"],"backgroundTag":"file-already-exists","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}