{"record":{"id":"39113e96e3fabd6f","repo":"tursodatabase/turso","slug":"self-test-failed-expected-export-was-not-found","errorCode":null,"errorMessage":"self-test failed: expected export was not found","messagePattern":"self-test failed: expected export was not found","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"critical","filePath":"bindings/dotnet/scripts/check_elf_dynsym_exports.py","lineNumber":38,"sourceCode":"        raise SystemExit(\"usage: check_elf_dynsym_exports.py <elf> <symbol>...\")\n\n    path = Path(sys.argv[1])\n    needed = sys.argv[2:]\n    missing = missing_exports(path, needed)\n    if missing:\n        raise SystemExit(f\"{path} is missing dynsym exports: {', '.join(missing)}\")\n\n\ndef run_self_test() -> None:\n    import tempfile\n\n    symbol = \"turso_sync_database_new\"\n    with tempfile.NamedTemporaryFile(delete=False, suffix=\".so\") as handle:\n        handle.write(elf64_with_dynsym(symbol))\n        path = Path(handle.name)\n    try:\n        if missing_exports(path, [symbol]):\n            raise SystemExit(\"self-test failed: expected export was not found\")\n        if not missing_exports(path, [\"turso_sync_database_missing\"]):\n            raise SystemExit(\"self-test failed: missing export was not reported\")\n    finally:\n        path.unlink()\n\n\ndef missing_exports(path: Path, needed: list[str]) -> list[str]:\n    names = dynsym_names(path)\n    return [symbol for symbol in needed if symbol not in names]\n\n\ndef elf64_with_dynsym(symbol: str) -> bytes:\n    shstrtab = b\"\\0.shstrtab\\0.dynstr\\0.dynsym\\0\"\n    dynstr = b\"\\0\" + symbol.encode(\"ascii\") + b\"\\0\"\n    dynsym = bytes(24) + struct.pack(\"<IBBHQQ\", 1, 0x12, 0, 1, 0x1000, 8)\n\n    shstrtab_offset = 64\n    dynstr_offset = shstrtab_offset + len(shstrtab)","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/tursodatabase/turso/blob/492c4a71cd7c2649e7df83da1471b74f4b1c7aa9/bindings/dotnet/scripts/check_elf_dynsym_exports.py#L20-L56","documentation":"The script's built-in --self-test generates a synthetic minimal ELF64 containing one dynsym symbol and verifies the checker finds it. This error means the self-test failed in the positive case: missing_exports() reported the genuinely-present symbol as missing, so the parsing logic is broken. It is an internal invariant failure of the tool itself, not of your ELF file.","triggerScenarios":"Running `check_elf_dynsym_exports.py --self-test` when missing_exports(path, [symbol]) returns non-empty for the synthetic ELF built by elf64_with_dynsym() — i.e. the parser failed to read back the symbol it just wrote.","commonSituations":"Someone edited elf64_with_dynsym(), the struct formats, section constants (NAME/TYPE/OFFSET/SIZE/LINK/ENTRY_SIZE), or names_from_dynsym() and broke the round-trip; also a Python/struct behavior change on an exotic platform.","solutions":["Check recent edits to elf64_with_dynsym(), elf_layout(), find_dynsym(), or names_from_dynsym() for format/offset regressions","Verify struct format strings match the section/symbol layouts (ELF64 section header is IIQQQQIIQQ, symbol is IBBHQQ)","Run the script under a debugger or add prints in names_from_dynsym() to see what names were actually parsed","Confirm entry_size and section offsets/alignment (dynsym_pad) are still computed correctly"],"exampleFix":"// before\nsymbols = struct.unpack_from(layout[\"symbol_format\"], data, offset)\n// wrong field index for name after changing struct layout\n// after\nsymbol = struct.unpack_from(layout[\"symbol_format\"], data, offset)\nraw = string_table[symbol[NAME]:]  # NAME == 0, keep constants in sync","handlingStrategy":"try-catch","validationCode":"subprocess.run([\"check_elf_dynsym_exports.py\", \"--self-test\"], check=True)  # gate edits on self-test passing","typeGuard":null,"tryCatchPattern":"try:\n    subprocess.run([\"check_elf_dynsym_exports.py\", \"--self-test\"], check=True)\nexcept subprocess.CalledProcessError as e:\n    print(\"self-test failed, checker logic is broken:\", e)\n    raise","preventionTips":["Run --self-test after any change to the ELF parsing or generation code","Keep struct format strings and field-index constants (NAME, TYPE, ...) in sync","Add round-trip coverage when changing elf64_with_dynsym()"],"tags":["self-test","python","internal-invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"492c4a71cd7c2649e7df83da1471b74f4b1c7aa9","analyzedAt":"2026-09-13T18:13:59.796Z","contentChangedAt":"2026-09-13T18:13:59.796Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}