foreach $j (@j) { alarm 2; # ^ You shouldn't set an alarm out of the scope where you eval the time out and localize $SIG{ALRM}; local $SIG{ALRM} = sub { die "timed out" }; # ^ This localization should be inside an eval block so you can catch the alarm. eval { callfc() }; # ^ Here, you are only catching errors from your function, not from a timeout next if $@ and $@ =~ /^timed out$/; # ^ You are checking for the exact string "timed out", but you should have /^timed out/ (without $ at the end), or, "timed out\n" in both places (including the new-line character) because otherwise the message will include traces information from "die" }