Bug #120105 mysql crash on fil_report_invalid_page_access_low
Submitted: 19 Mar 7:42 Modified: 10 Apr 12:23
Reporter: yangyang wang Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S2 (Serious)
Version:8.0.22 OS:Any
Assigned to: CPU Architecture:Any

[19 Mar 7:42] yangyang wang
Description:
mysql crash in Parallel_reader:
2026-03-15T10:57:23.739696+08:00 0 139736555788032 [&Parallel_reade] [System] [MY-011825] [InnoDB] &Parallel_reader::worker start.
2026-03-15T10:57:23.745280+08:00 0 139736555788032 [&Parallel_reade] [System] [MY-011825] [InnoDB] &Parallel_reader::worker start.
2026-03-15T10:57:23.752519+08:00 0 139736555788032 [&Parallel_reade] [System] [MY-011825] [InnoDB] &Parallel_reader::worker start.
2026-03-15T10:57:23.755435+08:00 0 139736539002624 [&Parallel_reade] [System] [MY-011825] [InnoDB] &Parallel_reader::worker start.
2026-03-15T10:57:23.758574+08:00 0 139736539002624 [&Parallel_reade] [ERROR] [MY-012153] [InnoDB] Trying to access page number 1768842857 in space 207060, space name db21146ye_228_72/t3, which is outside the tablespace bounds. Byte offset 0, len 16384, i/o type read. If you get this error at mysqld startup, please check that your my.cnf matches the ibdata 
files that you have in the MySQL server.
2026-03-15T10:57:23.758604+08:00 0 139736539002624 [&Parallel_reade] [ERROR] [MY-012154] [InnoDB] Server exits.
2026-03-15T10:57:23.758623+08:00 0 139736539002624 [&Parallel_reade] [ERROR] [MY-013183] [InnoDB] Assertion failure: fil0fil.cc:8437 thread 139736539002624
 

the stack is:
(gdb) bt
#0  0x00007f5c6c6f4a01 in pthread_kill () from /lib64/libpthread.so.0
#1  0x000000000140f2db in my_write_core (sig=6) at ../../../include/my_thread.h:91
#2  handle_fatal_signal (sig=6) at ../../sql/signal_handler.cc:171
#3  handle_fatal_signal (sig=6) at ../../sql/signal_handler.cc:75
#4  <signal handler called>
#5  0x00007f5c69dd64e7 in raise () from /lib64/libc.so.6
#6  0x00007f5c69dd7bd8 in abort () from /lib64/libc.so.6
#7  0x000000000251a056 in ut_dbg_assertion_failed (expr=0x0, file=0x3b71090 "../../../storage/innobase/fil/fil0fil.cc", line=8437) at ../../../storage/innobase/ut/ut0dbg.cc:127
#8  0x0000000003109684 in fil_report_invalid_page_access_low(unsigned int, unsigned int, char const*, unsigned long, unsigned long, bool, int) [clone .constprop.0] (block_offset=1768842857, space_id=74768, space_name=0x7f570bc9c460 "db21146ye_6038_180/t33", byte_offset=0, len=16384, is_read=<optimized out>, 
    line=<optimized out>) at ../../../storage/innobase/fil/fil0fil.cc:8437
#9  0x0000000006ce05db in Fil_shard::prepare_fil_space(IORequest const&, bool, page_id_t const&, buf_page_t*, sal_read_out_t*, unsigned long, unsigned long, fil_space_t*&, fil_node_t*&) [clone .cold.0] () at ../../../storage/innobase/fil/fil0fil.cc:8681
#10 0x00000000066c2bc9 in Fil_shard::do_io (this=0x7f5c4d1fd920, type=..., sync=<optimized out>, page_id=..., page_size=..., byte_offset=byte_offset@entry=0, len=16384, buf=0x7f5c0a5dc000, buf_page=0x7f5c07253a00, page_context=0x7f5536fd7430, ndp=0x0) at ../../../storage/innobase/fil/fil0fil.cc:8954
#11 0x0000000006669033 in fil_io (ndp=0x0, page_context=0x7f5536fd7430, message=0x7f5c07253a00, buf=0x7f5c0a5dc000, len=<optimized out>, byte_offset=0, page_size=..., page_id=..., sync=<optimized out>, type=...) at ../../../storage/innobase/fsp/fsp0fsp.cc:272
#12 buf_read_page_low (err=0x7f5536fd766c, sync=<optimized out>, type=0, mode=<optimized out>, page_id=..., page_size=..., unzip=false, anchor_page_p=0x7f5536fd7b88, page_load=NORMAL, is_scan=false) at ../../../storage/innobase/buf/buf0rea.cc:182
#13 0x0000000006668aaf in Buf_fetch<Buf_fetch_other>::read_page (this=0x7f5536fd7b20) at ../../../storage/innobase/buf/buf0buf.cc:4494
#14 0x00000000066824a9 in get (block=<optimized out>, this=<optimized out>) at ../../../storage/innobase/buf/buf0buf.cc:4084
#15 Buf_fetch<Buf_fetch_other>::single_page (this=0x7f5536fd7b20) at ../../../storage/innobase/buf/buf0buf.cc:4716
#16 0x00000000066114fb in buf_page_get_gen (dirty_with_no_latch=false, mtr=<optimized out>, line=<optimized out>, file=<optimized out>, mode=<optimized out>, guess=<optimized out>, rw_latch=1, page_size=..., page_id=...) at ../../../storage/innobase/include/ibuf0ibuf.ic:126
#17 buf_page_get_gen (dirty_with_no_latch=false, mtr=<optimized out>, line=<optimized out>, file=<optimized out>, mode=SCAN, guess=<optimized out>, rw_latch=1, page_size=..., page_id=...) at ../../../storage/innobase/buf/buf0buf.cc:4890
#18 btr_cur_search_to_nth_level (index=0x7f573aa09f98, level=<optimized out>, tuple=<optimized out>, mode=<optimized out>, latch_mode=<optimized out>, cursor=<optimized out>, has_search_latch=<optimized out>, file=<optimized out>, line=<optimized out>, mtr=<optimized out>, btr_ndp=<optimized out>)
    at ../../../storage/innobase/btr/btr0cur.cc:1482
#19 0x0000000006799475 in btr_pcur_t::open_no_init_low (this=this@entry=0x7f571d957698, index=index@entry=0x7f573aa09f98, tuple=tuple@entry=0x7f573abe6458, mode=PAGE_CUR_LE, latch_mode=latch_mode@entry=1, has_search_latch=has_search_latch@entry=0, mtr=<optimized out>, ndp_work=<optimized out>, 
    restore=<optimized out>, file=<optimized out>, line=<optimized out>) at ../../../storage/innobase/include/btr0pcur.h:831
#20 0x0000000006608d36 in btr_pcur_t::restore_position (this=0x7f571d957698, latch_mode=1, mtr=0x7f5536fd8d60, file=0x43907a8 "../../../storage/innobase/row/row0pread.cc", line=337) at ../../../storage/innobase/btr/btr0pcur.cc:300
#21 0x00000000069e0070 in restore_position (this=0x7f5536fd8d40) at ../../../storage/innobase/row/row0pread.cc:663
#22 Parallel_reader::Ctx::traverse (this=0x7f5721ceb1a0) at ../../../storage/innobase/row/row0pread.cc:664
#23 0x00000000069a9f2b in Parallel_reader::worker (this=0x7f570d490840, thread_ctx=<optimized out>) at ../../../storage/innobase/row/row0pread.cc:893
#24 0x00000000069ef88c in __invoke_impl<void, void (Parallel_reader::*&)(Parallel_reader::Thread_ctx*), Parallel_reader*&, Parallel_reader::Thread_ctx*&> (__t=<synthetic pointer>, __f=<synthetic pointer>) at ../../../storage/innobase/include/ut0ut.h:699
#25 __invoke<void (Parallel_reader::*&)(Parallel_reader::Thread_ctx*), Parallel_reader*&, Parallel_reader::Thread_ctx*&> (__fn=<synthetic pointer>) at /data/fuxi_ci_workspace/128467191/Taurus_x86/src/tools/gcc-10/include/c++/10/bits/invoke.h:95
#26 __call<void, 0, 1> (__args=<optimized out>, this=<synthetic pointer>) at /data/fuxi_ci_workspace/128467191/Taurus_x86/src/tools/gcc-10/include/c++/10/functional:416
#27 operator()<> (this=<synthetic pointer>) at /data/fuxi_ci_workspace/128467191/Taurus_x86/src/tools/gcc-10/include/c++/10/functional:499
#28 Runnable::operator()<void (Parallel_reader::*)(Parallel_reader::Thread_ctx*), Parallel_reader*, Parallel_reader::Thread_ctx*>(void (Parallel_reader::*&&)(Parallel_reader::Thread_ctx*), Parallel_reader*&&, Parallel_reader::Thread_ctx*&&) (this=0x7f56fe93b108, f=<optimized out>)
    at ../../../storage/innobase/include/os0thread-create.h:116
#29 0x0000000006907dd0 in execute_native_thread_routine () at ../../../storage/innobase/include/mach0data.ic:629
#30 0x00007f5c6c6efe15 in ?? () from /lib64/libpthread.so.0
#31 0x00007f5c69ea1fed in clone () from /lib64/libc.so.6

How to repeat:
use ddlcheck tool and restart mysqld random
[19 Mar 7:44] yangyang wang
The data is not damaged, and I can query the data normally after the restart.
[19 Mar 7:46] yangyang wang
Strangely, I found that the space accessed by the worker thread is not the same as the table accessed by the leader thread, and the SQL in the leader thread does not seem to need to go through the PQ logic (currently, PQ only supports count(*) and check table?).

 m_leader_thd = 0x7f56fd48d800}
(gdb) p (THD*)  0x7f56fd48d800
$28 = (THD *) 0x7f56fd48d800
(gdb) p ((THD*)0x7f56fd48d800)->m_query_string
$29 = {str = 0x7f570ab9a030 "ANALYZE TABLE t33 UPDATE HISTOGRAM ON c12", length = 41}

(gdb) p page_id
$5 = (const page_id_t &) @0x7f5536fd7a68: {m_space = 74768, m_page_no = 1768842857}

(gdb) p *space
$12 = {m_last_extended = {m_start = {__d = {__r = 32791027984465177}}}, m_undo_extend = 1024, name = 0x7f570bc9c460 "db21146ye_6038_180/t33", id = 74768,
[19 Mar 8:26] yangyang wang
Sorry,The space is the same, and the operation performed is 'ANALYZE TABLE t33 UPDATE HISTOGRAM ON c12'. During the read, the page number is out of the range.
[20 Mar 6:52] Mayank Prasad
Hi yangyang wang,

Thanks for filing the bug. 

However, "use ddlcheck tool and restart mysqld random" are not very clear reproduction steps. Is there some other tool you are using?

Could you please provide more specific reproduction steps.
[20 Mar 7:18] yangyang wang
We also used other tools, such as pstress. Currently, this is the only tool where this issue has been encountered, and not just once, but multiple times when the PQ scenario is enabled.

mysqld.err.2:2026-03-15T10:57:23.758574+08:00 0 139736539002624 [&Parallel_reade] [ERROR] [MY-012153] [InnoDB] Trying to access page number 1768842857 in space 207060, space name db21146ye_228_72/t3, which is outside the tablespace bounds. Byte offset 0, len 16384, i/o type read. If you get this error at mysqld startup, please check that your my.cnf matches the ibdata files that you have in the MySQL server.
mysqld.err.3:2026-03-15T10:45:50.526516+08:00 0 140205386364672 [&Parallel_reade] [ERROR] [MY-012153] [InnoDB] Trying to access page number 1768842857 in space 178665, space name db21146ye_8081_334/t52, which is outside the tablespace bounds. Byte offset 0, len 16384, i/o type read. If you get this error at mysqld startup, please check that your my.cnf matches the ibdata files that you have in the MySQL server.
mysqld.err.5:2026-03-15T09:49:36.189251+08:00 0 139924249368320 [&Parallel_reade] [ERROR] [MY-012153] [InnoDB] Trying to access page number 1768842857 in space 62312, space name db21146ye_6038_7/t24, which is outside the tablespace bounds. Byte offset 0, len 16384, i/o type read. If you get this error at mysqld startup, please check that your my.cnf matches the ibdata files that you have in the MySQL server.
mysqld.err.5:2026-03-15T09:56:27.924381+08:00 0 140003971548928 [&Parallel_reade] [ERROR] [MY-012153] [InnoDB] Trying to access page number 1768842857 in space 74768, space name db21146ye_6038_180/t33, which is outside the tablespace bounds. Byte offset 0, len 16384, i/o type read. If you get this error at mysqld startup, please check that your my.cnf matches the ibdata files that you have in the MySQL server.
[24 Mar 5:02] Mayank Prasad
Hi yangyang wang,

I am not aware of this ddlcheck tool. Could you please gprovideive detailed reproduction steps for the issue.

Thanks!
[25 Mar 8:20] yangyang wang
set innodb_buffer_pool_size to 10M,and run script, we can get the crash:

#!/bin/bash

export taurus_root_path=/opt/workdir/w00574625/mysql-root
export taurus_install_path=/home/ci/install

# 10 张表的名称(根据实际修改)
TABLES=(t3 t4 t5 t6 t7 t8 t9 t10 t1 t2)

MYSQL_DB="test"

# ==================== 函数定义 ====================
# 执行 ANALYZE TABLE 的无限循环
analyze_table() {
    while true; do
        # 随机选择一张表
        table=${TABLES[$RANDOM % ${#TABLES[@]}]}
        ${taurus_install_path}/sql/bin/mysql -h 127.0.0.1 -u root -P 3306 -p123456 -D"$MYSQL_DB"\
              -e "ANALYZE TABLE $table UPDATE HISTOGRAM ON c7;" > /dev/null 2>&1
        # 如需降低频率,可取消注释下面一行
        # sleep 0.1
    done
}

# 执行 SELECT COUNT(*) 的无限循环
select_count() {
    while true; do
        # 随机选择一张表
        table=${TABLES[$RANDOM % ${#TABLES[@]}]}
        ${taurus_install_path}/sql/bin/mysql -h 127.0.0.1 -u root -P 3306 -p123456 -D"$MYSQL_DB" \
              -e "SELECT COUNT(*) FROM $table;" > /dev/null 2>&1
        # 如需降低频率,可取消注释下面一行
        # sleep 0.1
    done
}

alter_table() {
    while true; do
        # 随机选择一张表
        table=${TABLES[$RANDOM % ${#TABLES[@]}]}
        ${taurus_install_path}/sql/bin/mysql -h 127.0.0.1 -u root -P 3306 -p123456 -D"$MYSQL_DB" \
              -e "optimize table $table;" > /dev/null 2>&1
        # 如需降低频率,可取消注释下面一行
        # sleep 0.1
    done
}

crud_view() {
    while true; do
        # 随机选择一张表
        table=${TABLES[$RANDOM % ${#TABLES[@]}]}
        ${taurus_install_path}/sql/bin/mysql -h 127.0.0.1 -u root -P 3306 -p123456 -D"$MYSQL_DB" \
              -e "CREATE VIEW $table_v AS SELECT c2 AS ca1, c5 AS ca2, c7 AS ca3 FROM $table WHERE ((! c7)); select * from $table_v;drop view $table_v;" > /dev/null 2>&1
        # 如需降低频率,可取消注释下面一行
        # sleep 0.1
    done
}

# ==================== 清理函数 ====================
cleanup() {
    echo -e "\nCaught signal, killing all background jobs..."
    # 杀死所有子进程
    kill $(jobs -p) 2>/dev/null
    wait
    exit
}

# ==================== 主逻辑 ====================
# 捕获退出信号
trap cleanup SIGINT SIGTERM

# 启动 30 个 ANALYZE 进程
for i in {1..30}; do
    analyze_table &
done

# 启动 20 个 SELECT 进程
for i in {1..20}; do
    select_count &
done

# 启动 20 个 SELECT 进程
for i in {1..5}; do
    alter_table &
done

for i in {1..5}; do
    crud_view &
done
echo "Started 30 ANALYZE and 20 SELECT processes. Press Ctrl+C to stop."

# 等待所有后台进程(永久等待)
wait
[26 Mar 7:22] yangyang wang
CREATE TABLE `t3` (
  `c7` float DEFAULT NULL,
  `c4` decimal(10,0) unsigned zerofill DEFAULT NULL,
  `c2` blob,
  `c5` smallint(5) unsigned zerofill DEFAULT NULL,
  UNIQUE KEY `c7` (`c7`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci STATS_PERSISTENT=1

prepare data:
CREATE PROCEDURE insert_t3_1m()
BEGIN
    DECLARE i INT DEFAULT 1;
    DECLARE max_rows INT DEFAULT 1000000;   -- 目标行数:100万
    DECLARE batch_size INT DEFAULT 1000;    -- 每1000行提交一次
    DECLARE rand_c4 DECIMAL(10,0);
    DECLARE rand_c2 BLOB;
    DECLARE rand_c5 SMALLINT UNSIGNED;

    SET autocommit = 0;                     -- 关闭自动提交,手动控制事务

    WHILE i <= max_rows DO
        -- 生成随机数据
        SET rand_c4 = FLOOR(RAND() * 10000000000);     -- 0 ~ 9,999,999,999
        SET rand_c2 = RANDOM_BYTES(100);               -- 100字节随机二进制数据
        SET rand_c5 = FLOOR(RAND() * 65536);           -- 0 ~ 65,535

        -- 插入数据,c7 使用循环变量 i 确保唯一性
        INSERT INTO t3 (c7, c4, c2, c5) VALUES (i, rand_c4, rand_c2, rand_c5);

        -- 每 batch_size 行提交一次,避免事务过大
        IF i % batch_size = 0 THEN
            COMMIT;
        END IF;

        SET i = i + 1;
    END WHILE;

    COMMIT;                                 -- 提交剩余未提交的行
    SET autocommit = 1;                     -- 恢复自动提交
END //

DELIMITER ;

create other tables:(t1~t10)
create table t1 select * from t3;
[10 Apr 11:06] Mayank Prasad
I tried it multiple times with the scripts given but wasn't able to repro it. I tried both on release and debug build but no luck.
[10 Apr 12:23] Shane Bester
Hello,

I've already tried repeating this on 8.0.22 and wasn't able to after an hour+ of running.   

Please check if 8.4.8 or 9.6.0 is affected by same bug, and if it is reopen this report.

Thanks,
[17 Apr 17:07] Jean-François Gagné
I was not able to reproduce either, but I did not run for very long (45 minutes with 66 restarts): how long does it take to get a crash ?  Our test environment might also be different (MySQL settings, hardware, ...).  Also, this was open for 8.0.22 (and I tested this version), but we should move tests to more recent 8.0.45 and 8.4.8.

I am doing tests on a m6id.8xlarge AWS VM (local SSDs, 128 vCPU and 64 cores), starting with default MySQL settings.  In addition to changing the InnoDB Buffer Pool Size, are you changing other parameters ?  Because this looks related to Parallel Reads, I tried with innodb_parallel_read_threads=16, but still no crash.

> when the PQ scenario is enabled

Are you doing anything specific to enable PQ / parallel query ?  How many CPUs do you have ?  What type of disks do you have (local SSDs, network SSDs, ...) ?

Below are my test scripts.  I modified / fixed crud_view because "CREATE VIEW $table_v" did not work (also dropped the view in another command to be resilient of a mysqld restart leaving a view present), implemented some "stop" features (touch run), and implemented some noise reduction (touch run_stop).  Note that I am getting some errors, two listed below (single-part unique index for t3, and deadlocks).  Also sometimes, mysqld stop hangs and I have to kill -9 (in restart_mysqld).

---

test_jfg.t3     histogram       Error   The column 'c7' is covered by a single-part unique index.

test_jfg.t9     histogram       Error   Deadlock found when trying to get lock; try restarting transaction

---

{
  v=mysql_8.0.22; d=${v//./_}
  dbda="-c innodb_buffer_pool_chunk_size=1048576 -c innodb_buffer_pool_instances=1"
  dbdeployer deploy single $v $dbda| pv -tN dbdepl. > /dev/null
  cd ~/sandboxes/msb_$d
}

{
  ./use <<< "CREATE DATABASE test_jfg"

  ./use test_jfg <<< "
    CREATE TABLE t3 (
      c7 float DEFAULT NULL,
      c4 decimal(10,0) unsigned zerofill DEFAULT NULL,
      c2 blob,
      c5 smallint(5) unsigned zerofill DEFAULT NULL,
      UNIQUE KEY c7 (c7)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci STATS_PERSISTENT=1;

    DELIMITER //

    CREATE PROCEDURE insert_t3_1m()
    BEGIN
      DECLARE i INT DEFAULT 1;
      DECLARE max_rows INT DEFAULT 1000000;
      DECLARE batch_size INT DEFAULT 1000;
      DECLARE rand_c4 DECIMAL(10,0);
      DECLARE rand_c2 BLOB;
      DECLARE rand_c5 SMALLINT UNSIGNED;

      SET autocommit = 0;

      WHILE i <= max_rows DO
        SET rand_c4 = FLOOR(RAND() * 10000000000);     -- 0 ~ 9,999,999,999
        SET rand_c2 = RANDOM_BYTES(100);
        SET rand_c5 = FLOOR(RAND() * 65536);           -- 0 ~ 65,535

        INSERT INTO t3 (c7, c4, c2, c5) VALUES (i, rand_c4, rand_c2, rand_c5);

        IF i % batch_size = 0 THEN
          COMMIT;
        END IF;

        SET i = i + 1;
      END WHILE;

      COMMIT;
      SET autocommit = 1;
    END //"

  ./use test_jfg <<< "CALL insert_t3_1m()" | pv -tN call

  for t in t4 t5 t6 t7 t8 t9 t10 t1 t2; do
    ./use test_jfg <<< "create table $t select * from t3" | pv -tN $t
  done
}

TABLES=(t3 t4 t5 t6 t7 t8 t9 t10 t1 t2)

analyze_table() {
    while test -e run; do
        test -e run_stop && { sleep 1; continue; }
        ./use test_jfg -N -e "ANALYZE TABLE ${TABLES[$RANDOM % ${#TABLES[@]}]} UPDATE HISTOGRAM ON c7"
    done
}

select_count() {
    while test -e run; do
        test -e run_stop && { sleep 1; continue; }
        ./use test_jfg -N -e "SELECT COUNT(*) FROM ${TABLES[$RANDOM % ${#TABLES[@]}]}"
    done
}

alter_table() {
    while test -e run; do
        test -e run_stop && { sleep 1; continue; }
        ./use test_jfg -N -e "optimize table ${TABLES[$RANDOM % ${#TABLES[@]}]}"
    done
}

crud_view() {
    local view=view_$1
    while test -e run; do
        test -e run_stop && { sleep 1; continue; }
        local table=${TABLES[$RANDOM % ${#TABLES[@]}]}
        local sql="CREATE VIEW $view AS SELECT c2 AS ca1, c5 AS ca2, c7 AS ca3 FROM $table WHERE ((! c7));"
        ./use test_jfg -N -e "$sql select * from $view;"
        ./use test_jfg -N -e "drop view $view;"
    done
}

restart_mysqld() {
  local i=1 pid
  while test -e run; do
    sleep $(($RANDOM % 60)); test -e run || break
    touch run_stop; pid=$(cat data/*.pid); pkill -9 mysqld_safe; kill $pid
    { for j in {0..9}; do sleep 1; ps -p $pid > /dev/null || break; done
      ps -p $pid > /dev/null && kill -9 $pid
      while ps -p $pid > /dev/null; do sleep 0.1; done
    } | pv -tN stop$i
    ./start; rm run_stop
    i=$(($i+1))
  done
}

run_test() {
  touch run; rm run_stop
  for i in {1..30}; do analyze_table & done
  for i in {1..20}; do select_count &  done
  for i in {1..5};  do alter_table &   done
  for i in {1..5};  do crud_view $i &  done
  restart_mysqld &
}

./use <<< "set persist innodb_buffer_pool_size = 1024*1024*10"
run_test | pv -tN run_test

./use <<< "set persist innodb_parallel_read_threads = 16"
run_test | pv -tN run_test
[17 Apr 17:11] Jean-François Gagné
> I am doing tests on a m6id.8xlarge AWS VM (local SSDs, 128 vCPU and 64 cores)

Sorry, above is wrong.  It is a m6id.32xlarge, other specs are ok.

Not to self: this instance is 7.5936 USD per Hour (and this is why I did not leave tests running for very long).
[31 Aug 17:48] Jakub Lopuszanski
This is related to 
https://bugs.mysql.com/bug.php?id=120136

In both cases the "page number" is 1768842857 
Which in hex is 
(1768842857).toString(16)
"696e6669" 
which in ASCII, is
String.fromCharCode( 0x69,0x6e,0x66,0x69)
"infi" 
Which in looks eerly familiar :D
Looks like an infimum record is being interpreted as a regular child record.
This suggests btr_pcur_t::restore_position -> open_no_init -> btr_cur_search_to_nth_level somewhere makes a mistake.
One possibility is that
```
page_id.reset(space, btr_node_ptr_get_child_page_no(node_ptr, offsets));
```
which is implemented roughly as "interpret the last field of the record as 4 byte page number" is called on a cursor which points to infimum.
This in turn could be because `page_cur_search_with_match(...PAGE_CUR_LE..)` in principle is allowed to position the cursor on infimum if the tuple sought is smaller than any regular record on the page.
The code seems to be written as if that case is not possible for internal nodes - that is I don't see the caller taking into account a possibility of the tuple sought being smaller than anything on the internal page.
Why?
Well, if you dive into the `cmp_dtuple_rec_with_match_low(..)` which is used by `dtuple_t::compare(..)` used in `page_cur_search_with_match(..)`, it has a special case handling for the first regular record on the page (i.e. the one which is right after "infimum"), which is to always treat it as smaller than the sought tuple.
This hack makes it (in theory) impossible to settle the cursor on the infimum, because whenever mid_rec points to the first regular record, this hack in the comparison forces the bisect logic to go to the right.
Yet, somehow we've ended up on the infimum anyway.
How could it be?

Well, one possibility is that my analysis above is wrong - the code is quite complex.

But the other is that this is yet another manifestation of another known bug:
Bug #110331 	InnoDB report Assertion failure at histogram sampler when transaction rollback
If you look there, the symptom is quite similar:
```
2023-03-10T05:36:14.613019Z 0 [ERROR] [MY-012153] [InnoDB] Trying to access page number 1094795585 in space 2, space name test/htable, which is outside the tablespace bounds. Byte offset 0, len 16384, i/o type  read. If you get this error at mysqld startup, please check that your my.cnf matches the ibdata files that you have in the MySQL server.
```
Yes, 1094795585 is not 1768842857, but in ASCII it is "AAAA", which matches the repro steps which involve `INSERT INTO `htable` (h_data) values (repeat('A', 1000));`
And we know, from analysing that other bug, that the root cause in Bug #110331 was that a page which was a leaf-page got interpreted as internal page.
And therefore the "AAAA" field was interpreted as child page number.
Now, in your current bug report, we end up on "infimum", not some user record, but perhaps we do so, for the same reason: we are actually doing bisect inside a leaf page, thinking it is an internal node.
And in a leaf page there is no REC_INFO_MIN_REC_FLAG set on the first regular record, so it is perfectly possible for the bisect to end up on "infimum".

Now, you may wonder how come a leaf page can get interpreted as a non-leaf page?
Basically the problem is that during Histogram sampling we do not properly latch the whole index tree, so it is possible for another thread to perform some serious modifications to it such as merges, splits, root-lift, or flattening, and it is therefore possible the tree got flatter than it used to be, perhaps to the point where it has just the leaf level (so the root is already at level 0)

That said, I must admit I didn't see how it could happen in parallel to the btr_cur_search_to_nth_level(..) in such a way as to trick it to think it is at a different level than it really is.
In the Bug #110331 the situation was simpler: the flattening already happened before btr_cur_search_to_nth_level(..) was even called, and it simply returned a node at a leaf level even though the caller asked for level=1, and then the problem manifested in the caller, not inside the btr_cur_search_to_nth_level(..) itself.

Also, IIUC the repro steps do not really involve massive DELETEs which could cause flattening.

So, another possibility is that the REC_INFO_MIN_REC_FLAG is not set, or is set on a wrong record.
We had a bug like that in the past, 
```
    Bug #34833609 Assertion failure: btr0load.cc:1489:rec_count <= n_recs thread 140094285530880

    There is an off-by-one error with respect to rec_count and i variable in
    the Page_load::copy_to() function. And set the REC_INFO_MIN_REC_FLAG in the
    newly added root page in Btree_load::Merger::root_split().
```
but this was fixed in 2022, yet the current bug report seems similar to Bug#120136 which reproducible on 8.0.41 which was released in 2024.

Another thing which seems important here is that we generally try hard to maintain a property that the value stored in regular internal page record is actually equal to the minimum in the child pointed, if that child is also an internal node. (We don't enforce that in case the child is a leaf-page, i.e. if you DELETE the smallest record on a leaf page, then we don't bother to update the parent. OTOH when we remove first record on internal node, then we do, recursively, "update" the parent, by removing the old tuple, and inserting a new one. )
We even seem to have debug checks for that in btr_validate_level(..) which emits `ib::error(ER_IB_MSG_42) << "Node ptrs differ on levels > 0";` on a mismatch.
Assuming this invariant indeed holds, then we should never really even need the REC_INFO_MIN_REC_FLAG special case (except in the root), because we would only descend to a given page if we saw in its parent a record which is <= than sought tuple, and thus we could prove that the current page also has to contain a record <= than that tuple.
[31 Aug 17:48] Jakub Lopuszanski
I've asked GPT-5.6 Terra Medium for opinion, and it strongly believes the explanation is that it is the same problem as in Bug #110331 - flattening of the tree happening before btr_cur_search_to_nth_level(..level=1..) even started, manifesting in a different way.
It's theory is the following:
The btr_cur_search_to_nth_level(..) has `height` variable which tracks at what level is the page we currently look at.
It is established as it should: by looking at page header. So if the flattening already occurred, then root page is the only page and is a leaf page, so has height=0.
The logic in `btr_cur_search_to_nth_level(..)` however, doesn't care check if height!=0 to determine if it should search for child or not!
Instead it compares `height` (0) to the desired `level` (1) and does so using `!=` instead of `>`:
```
if (level != height) {
```
This means, that if the `level` is greater than `height` already, then we handle this case as if we are in internal node, even if `height=0`.

I must say GPT's theory sounds legit.

But then it remains to explain how come the tree got flat?

You didn't share what ddlcheck tool is, but I found
https://wsdou.github.io/papers/2025-vldb-ddlcheck.pdf paper, which references
https://figshare.com/s/e222bd56c4925375ac34 in which I found a zip with some source code.

The other bug#120136 contained this invocation:
```
java -jar target/ddlcheck1.0-1.0.0.jar --num-threads 150 --log  --num-tries 2300 --num-queries 500 --string-constant-max-length 512 --max-num-inserts 50 --max-expression-depth 3 --max-production-recursion 3
--max-generated-databases -1 --host 192.168.1.222 --port 3306 --username root --password  --database-prefix $DB_PREFIX  --use-constant-caching false --dml_max 200 --ddl_max 200  mysql
```
This doesn't seem to match the source I found, as it doesn't understand dml_max argument, but assuming that it means running DMLs in parallel to the histogram sampler, and given the grammar file contains
```
# DELETE
delete:
    DELETE LOW_PRIORITY? QUICK? IGNORE? FROM _table where_clause?
    | DELETE LOW_PRIORITY? QUICK? IGNORE? FROM _table where_clause
    @enable-oracle transaction_verifier
    | DELETE LOW_PRIORITY? QUICK? IGNORE? FROM _table where_clause
    @enable-oracle transaction_verifier
    | DELETE LOW_PRIORITY? QUICK? IGNORE? FROM _table
```
it seems plausible that some DELETE operations caused flattening of the tree.

The only remaining problem in this whole theory is that you have also shared what appears to be a bash script which you've claimed to also reproduce the issue, but I don't see any usage of DELETE in it, just SELECTs and various ALTERs/OPTIMIZEs and VIEW creations/drops, but nothing which could obviously lead to tree flattening.
That said, nobody on else was able to reproduce the issue using this bash scripts, so perhaps there's some misunderstanding on how to use them, or what they reproduce?