In Ruby gli errori sono oggetti (Exception) che si sollevano con raise e si catturano con rescue.

def leggi_config(path)
  File.read(path)
rescue Errno::ENOENT
  puts "File non trovato, uso i default"
  "{}"
rescue JSON::ParserError => e
  raise "Config non valida: #{e.message}"
ensure
  puts "Tentativo di lettura completato"
end

Cattura classi specifiche, non tutto: un rescue nudo (senza classe) prende anche errori che non ti aspetti e nasconde bug veri. ensure gira sempre, con o senza errore: perfetto per chiudere file e connessioni.

Puoi anche usare retry dentro un rescue per ritentare (utile con le reti instabili). Ma metti un contatore, o rischi un loop infinito. La regola: cattura solo ciò che sai gestire, lascia esplodere il resto.