Solidity Try Catch
Try catch is a way to handle a failed external call without reverting the caller. The caller runs a backup branch instead of failing with the callee.
Try catch keeps the caller alive on failure
Worker fails when asked. Caller catches that failure and reports it instead of reverting.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract Worker {
function work(bool fail) public pure {
require(!fail, "work failed");
}
}
contract Caller {
Worker public worker;
constructor(address workerAddress) {
worker = Worker(workerAddress);
}
function attempt(bool fail) public returns (bool) {
bool ok;
try worker.work(fail) {
ok = true;
} catch {
ok = false;
}
return ok;
}
}
Try catch can capture a return value
The try branch captures the computed value. The catch branch supplies a fallback pair instead.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract Worker {
function compute(uint256 x) public pure returns (uint256) {
require(x > 0, "x must be above zero");
return x * 3;
}
}
contract Caller {
Worker public worker;
constructor(address workerAddress) {
worker = Worker(workerAddress);
}
function tryCompute(uint256 x) public returns (bool, uint256) {
try worker.compute(x) returns (uint256 v) {
return (true, v);
} catch {
return (false, 0);
}
}
}
Try catch cannot wrap an internal call
An internal call inside try fails to compile. Try catch is only for calls that cross a contract boundary.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract Inner {
function helper() internal pure returns (uint256) {
return 7;
}
function run() public pure returns (uint256) {
uint256 v;
try helper() returns (uint256 r) {
v = r;
} catch {
v = 0;
}
return v;
}
}
Example
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract Service {
function getPrice(bool fail) public pure returns (uint256) {
require(!fail, "service failed");
return 100;
}
}
contract Consumer {
Service public service;
constructor(address serviceAddress) {
service = Service(serviceAddress);
}
function priceOrFallback(bool fail) public returns (uint256) {
try service.getPrice(fail) returns (uint256 price) {
return price;
} catch {
return 42;
}
}
}
Key points
- Try catch: a handler that runs one branch on success and another on failure.
- Use try catch to keep a caller alive when an outside call fails.
- Try catch works only on external calls and on contract creation.
- A try branch can capture a return value from the outside call.
- A plain catch branch runs for any failure, whatever its cause.
In this example, Service returns a price or fails when asked. Consumer stores the service and calls it inside try. Its priceOrFallback function returns the real price on success and the fallback value 42 on failure.
Note
try catch never works on an internal function call, so internal failures still revert the caller.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Remix IDE
Exercise
Which call can try catch handle?