bytecodeHash wrong type throws uncaught json exception
- Dominant language
- C++
- Stars
- 25.7k
- Forks
- 6.2k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 21
Description
## Description
When a standard-json input contains `settings.metadata.bytecodeHash` set to a value that is not a string (e.g. an integer, `null`, an array, an object, or a boolean), the compiler throws an uncaught `nlohmann::json::type_error`. The exception propagates out of the validator and surfaces in the JSON output as an `"Uncaught exception"` error that leaks the bundled `nlohmann::json` ABI version and the C++ exception type name.
The validator at `libsolidity/interface/StandardCompiler.cpp:573` calls `.get()` on the field without first checking `is_string()`:
```cpp
static std::set hashes{"ipfs", "bzzr1", "none"};
if (_input.contains("bytecodeHash") &&
!hashes.count(_input["bytecodeHash"].get())) // no is_string() precheck
return formatFatalError(Error::Type::JSONError,
"\"settings.metadata.bytecodeHash\" must be \"ipfs\", \"bzzr1\" or \"none\"");
```
The two immediately-preceding sibling validators in the same `checkMetadataKeys` function (lines 567-569) use proper `!is_boolean()` prechecks:
```cpp
if (_input.contains("appendCBOR") && !_input["appendCBOR"].is_boolean())
return formatFatalError(JSONError, "...appendCBOR must be Boolean");
if (_input.contains("useLiteralContent") && !_input["useLiteralContent"].is_boolean())
return formatFatalError(JSONError, "...useLiteralContent must be Boolean");
```
Every other `.get()` call in the standard-json validator (`evmVersion`, `stopAfter`, `debug.revertStrings`, `modelChecker.engine`/`extCalls`, `libraries.`, `optimizer.details.yulDetails.optimizerSteps`) is preceded by `is_string()` and produces a clean typed error; only `bytecodeHash` slips through.
Observed behavior:
| `bytecodeHash` value | result |
| --- | --- |
| `"ipfs"` / `"bzzr1"` / `"none"` | OK |
| `"bogus"` | clean error: `must be "ipfs", "bzzr1" or "none"` |
| `42`, `null`, `[]`, `{}`, `true` | uncaught `nlohmann::json::type_error` |
The wrong-value-correct-type case is properly rejected with a typed error; the wrong-type case bypasses validation entirely and leaks an internal exception of the form:
```
Dynamic exception type: nlohmann::json_abi_v3_12_0::detail::type_error
std::exception::what: [json.exception.type_error.302] ...
```
Expected: a typed JSON error message indicating that `settings.metadata.bytecodeHash` must be a string (consistent with the sibling validators in the same function).
Fix: add an `is_string()` precheck before line 573's `.get()`.
## Environment
- Compiler version: 0.8.35-develop.2026.5.5+commit.47b9dedd.Linux.g++
- Operating system: Linux Ubuntu Jammy
## Steps to Reproduce
Feed the following standard-json input to `solc --standard-json` (any non-string value for `settings.metadata.bytecodeHash` reproduces — `42`, `null`, `[]`, `{}`, or `true`):
```json
{
"language": "Solidity",
"sources": {
"A.sol": { "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity *;\ncontract A {}" }
},
"settings": {
"metadata": {
"bytecodeHash": 42
}
}
}
```
Result: the response contains an `"Uncaught exception"` error citing `nlohmann::json_abi_v3_12_0::detail::type_error` / `[json.exception.type_error.302]` instead of the expected typed error message.
For comparison, replacing `42` with the string `"bogus"` produces the clean error:
```
"settings.metadata.bytecodeHash" must be "ipfs", "bzzr1" or "none"
```
A scripted verifier is available at `research/scripts/verify_E352b89.sh`, which exercises all five wrong-type variants:
```
$ bash research/scripts/verify_E352b89.sh
bytecodeHash=42 -> uncaught nlohmann type_error
bytecodeHash=null -> uncaught nlohmann type_error
bytecodeHash=[] -> uncaught nlohmann type_error
bytecodeHash={} -> uncaught nlohmann type_error
bytecodeHash=true -> uncaught nlohmann type_error
OK: StandardCompiler.cpp:573 bytecodeHash missing is_string precheck
```
Contributor guide
Assessment
This issue has not been assessed yet.