diff --git a/plugins/sql.c b/plugins/sql.c index 1490b5063955..f066ab9893c8 100644 --- a/plugins/sql.c +++ b/plugins/sql.c @@ -534,7 +534,11 @@ static struct command_result *process_json_obj(struct command *cmd, if (!col->sub->is_subobject) continue; - coltok = json_get_member(buf, t, col->jsonname); + /* This can happen if the field is missing */ + if (!t) + coltok = NULL; + else + coltok = json_get_member(buf, t, col->jsonname); ret = process_json_obj(cmd, buf, coltok, col->sub, row, this_rowid, NULL, sqloff, stmt); if (ret) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 0c4edc319d86..97c2c6d8e6de 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -4395,3 +4395,23 @@ def test_autoclean_batch(node_factory): l1.rpc.setconfig('autoclean-cycle', 5) wait_for(lambda: l1.rpc.autoclean_status('expiredinvoices') == {'autoclean': {'expiredinvoices': {'enabled': True, 'cleaned': 200, 'age': 2}}}) + + +def test_sql_crash(node_factory, bitcoind): + """sub-object with inner-sub-object is missing -> Crash. This only + happens for local and remote inside listpeerchannels.update (for + now). + + """ + l1, l2 = node_factory.line_graph(2, fundchannel=False) + + addr = l1.rpc.newaddr()['bech32'] + bitcoind.rpc.sendtoaddress(addr, 1) + bitcoind.generate_block(1) + + wait_for(lambda: l1.rpc.listfunds()['outputs'] != []) + + l1.rpc.fundchannel_start(l2.info['id'], '10000000sat') + + assert 'updates' not in only_one(l1.rpc.listpeerchannels()['channels']) + l1.rpc.sql(f"SELECT * FROM peerchannels;")