Skip to main content

A search-based decoder for quantum error correction (QEC).

Project description

Tesseract Decoder

A Search-Based Decoder for Quantum Error Correction.

Licensed under the Apache 2.0 open-source license C++

InstallationUsagePython InterfacePaperHelpCitationContact

Tesseract is a Most Likely Error decoder designed for Low Density Parity Check (LDPC) quantum error-correcting codes. It applies pruning heuristics and manifold orientation techniques during a search over the error subsets to identify the most likely error configuration consistent with the observed syndrome. Tesseract achieves significant speed improvements over traditional integer programming-based decoders while maintaining comparable accuracy at moderate physical error rates.

We tested the Tesseract decoder for:

  • Surface codes
  • Color codes
  • Bivariate-bicycle codes
  • Transversal CNOT protocols for surface codes

Features

  • A* search: deploys A* search while running a Dijkstra algorithm with early stop for high performance.
  • Stim and DEM Support: processes Stim circuit files and Detector Error Model (DEM) files with arbitrary error models. Zero-probability error instructions are automatically removed when a DEM is loaded.
  • Parallel Decoding: uses multithreading to accelerate the decoding process, making it suitable for large-scale simulations.
  • Efficient Beam Search: implements a beam search algorithm to minimize decoding cost and enhance efficiency. Sampling and Shot Range Processing: supports sampling shots from circuits. When a detection error model is provided without an accompanying circuit, Tesseract requires detection events from files using --in. The decoder can also process specific shot ranges for flexible experiment setups.
  • Detailed Statistics: provides comprehensive statistics output, including shot counts, error counts, and processing times.
  • Heuristics: includes flexible heuristic options: --beam, --det-penalty, --beam-climbing, --no-revisit-dets, --at-most-two-errors-per-detector, and --pqlimit to improve performance while maintaining a low logical error rate. To learn more about these options, use ./bazel-bin/src/tesseract --help
  • Visualization tool: open the viz directory in your browser to view decoding results. See viz/README.md for instructions on generating the visualization JSON.

Installation

Tesseract relies on the following external libraries:

  • argparse: For command-line argument parsing.
  • nlohmann/json: For JSON handling (used for statistics output).
  • Stim: For quantum circuit simulation and error model handling.

Build Instructions

Tesseract uses Bazel as its build system. To build the decoder:

bazel build src:all

Running Tests

Unit tests are executed with Bazel. Run the quick test suite using:

bazel test //src:all

By default the tests use reduced parameters and finish in under 30 seconds. To run a more exhaustive suite with additional shots and larger distances, set:

TESSERACT_LONG_TESTS=1 bazel test //src:all

Usage

The file tesseract_main.cc provides the main entry point for Tesseract Decoder. It can decode error events from Stim circuits, DEM files, and pre-existing detection event files.

Basic Usage:

./tesseract --circuit CIRCUIT_FILE.stim --sample-num-shots N --print-stats

To decode pre-generated detection events, provide the input file using --in SHOTS_FILE --in-format FORMAT.

Example with Advanced Options:

./tesseract \
        --pqlimit 1000000 \
        --at-most-two-errors-per-detector \
        --det-order-seed 232852747 \
        --circuit circuit_file.stim \
        --sample-seed 232856747 \
        --sample-num-shots 10000 \
        --threads 32 \
        --print-stats \
        --beam 23 \
        --num-det-orders 1 \
        --shot-range-begin 582 \
        --shot-range-end 583

Example Usage

Sampling Shots from a Circuit:

./tesseract --circuit surface_code.stim --sample-num-shots 1000 --out predictions.01 --out-format 01

Using a Detection Event File:

./tesseract --in events.01 --in-format 01 --dem surface_code.dem --out decoded.txt

Using a Detection Event File and Observable Flips:

./tesseract --in events.01 --in-format 01 --obs_in obs.01 --obs-in-format 01 --dem surface_code.dem --out decoded.txt

Tesseract supports reading and writing from all of Stim's standard output formats.

Performance Optimization

Here are some tips for improving performance:

  • Parallelism over shots: increase --threads to leverage multicore processors for faster decoding.
  • Beam Search: use --beam to control the trade-off between accuracy and speed. Smaller beam sizes result in faster decoding but potentially lower accuracy.
  • Beam Climbing: enable --beam-climbing for enhanced cost-based decoding.
  • At most two errors per detector: enable --at-most-two-errors-per-detector to improve performance.
  • Priority Queue limit: use --pqlimit to limit the size of the priority queue.

Output Formats

  • Observable flips output: predictions of logical errors.
  • DEM usage frequency output: if --dem-out is specified, outputs estimated error frequencies.
  • Statistics output: includes number of shots, errors, low confidence shots, and processing time.

Python Interface

Full Python wrapper documentation

This repository contains the C++ implementation of the Tesseract quantum error correction decoder, along with a Python wrapper. The Python wrapper/interface exposes the decoding algorithms and helper utilities, allowing Python users to leverage this high-performance decoding algorithm.

For installation:

pip install tesseract-decoder

The following example demonstrates how to create and use the Tesseract decoder using the Python interface.

from tesseract_decoder import tesseract
import stim
import numpy as np


# 1. Define a detector error model (DEM)
dem = stim.DetectorErrorModel("""
    error(0.1) D0 D1 L0
    error(0.2) D1 D2 L1
    detector(0, 0, 0) D0
    detector(1, 0, 0) D1
    detector(2, 0, 0) D2
""")

# 2. Create the decoder configuration
config = tesseract.TesseractConfig(dem=dem, det_beam=50)

# 3. Create a decoder instance
decoder = config.compile_decoder()

# 4. Simulate detector outcomes
syndrome = np.array([0, 1, 1], dtype=bool)

# 5a. Decode to observables
flipped_observables = decoder.decode(syndrome)
print(f"Flipped observables: {flipped_observables}")

# 5b. Alternatively, decode to errors
decoder.decode_to_errors(syndrome)
predicted_errors = decoder.predicted_errors_buffer
# Indices of predicted errors
print(f"Predicted errors indices: {predicted_errors}")
# Print properties of predicted errors
for i in predicted_errors:
    print(f"    {i}: {decoder.errors[i]}")

Using Tesseract with Sinter

Tesseract can be easily integrated into Sinter workflows. Sinter is a tool for running and organizing quantum error correction simulations.

Here's an example of how to use Tesseract as a decoder for multiple Sinter tasks:

import stim
import sinter
from tesseract_decoder import make_tesseract_sinter_decoders_dict, TesseractSinterDecoder
import tesseract_decoder

if __name__ == "__main__":  
    # Define a list of Sinter task(s) with different circuits/decoders.
    tasks = []
    # Depolarizing noise probability.
    p = 0.005
    # These are the sensible defaults given by make_tesseract_sinter_decoders_dict().
    # Note that `tesseract-short-beam` and `tesseract-long-beam` are the two sets of parameters used in the [Tesseract paper](https://arxiv.org/pdf/2503.10988).
    decoders = ['tesseract', 'tesseract-long-beam', 'tesseract-short-beam']
    decoder_dict = make_tesseract_sinter_decoders_dict()
    # You can also make your own custom Tesseract Decoder to-be-used with Sinter.
    decoders.append('custom-tesseract-decoder')
    decoder_dict['custom-tesseract-decoder'] = TesseractSinterDecoder(
        det_beam=10,
        beam_climbing=True,
        no_revisit_dets=True,
        merge_errors=True,
        pqlimit=1_000,
        num_det_orders=5,
        det_order_method=tesseract_decoder.utils.DetOrder.DetIndex,
        seed=2384753,
    )

    for distance in [3, 5, 7]:
        for decoder in decoders:
            circuit = stim.Circuit.generated(
                "surface_code:rotated_memory_x",
                distance=distance,
                rounds=3,
                after_clifford_depolarization=p
            )
            tasks.append(sinter.Task(
                circuit=circuit,
                decoder=decoder,
                json_metadata={"d": distance, "decoder": decoder},
            ))

    # Collect decoding outcomes per task from Sinter.
    results = sinter.collect(
        num_workers=8,
        tasks=tasks,
        max_shots=10_000,
        decoders=decoders,
        custom_decoders=decoder_dict,
        print_progress=True,
    )

    # Print samples as CSV data.
    print(sinter.CSV_HEADER)
    for sample in results:
        print(sample.to_csv_line())

should get something like:

    shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts  
    10000,        42,         0,   0.071,tesseract,1b3fce6286e438f38c00c8f6a5005947373515ab08e6446a7dd9ecdbef12d4cc,"{""d"":3,""decoder"":""tesseract""}",  
    10000,        49,         0,   0.546,custom-tesseract-decoder,7b082bec7541be858e239d7828a432e329cd448356bbdf051b8b8aa76c86625a,"{""d"":3,""decoder"":""custom-tesseract-decoder""}", 
    10000,        13,         0,    7.64,tesseract-long-beam,217a3542f56319924576658a6da7081ea2833f5167cf6d77fbc7071548e386a9,"{""d"":5,""decoder"":""tesseract-long-beam""}",  
    10000,        42,         0,   0.743,tesseract-short-beam,cf4a4b0ce0e4c7beec1171f58eddffe403ed7359db5016fca2e16174ea577057,"{""d"":3,""decoder"":""tesseract-short-beam""}",  
    10000,        34,         0,   0.924,tesseract-long-beam,8cfa0f2e4061629e13bc98fe213285dc00eb90f21bba36e08c76bcdf213a1c09,"{""d"":3,""decoder"":""tesseract-long-beam""}",  
    10000,        10,         0,   0.439,tesseract,8274ea5ffec15d6e71faed5ee1057cdd7e497cbaee4c6109784f8a74669d7f96,"{""d"":5,""decoder"":""tesseract""}",  
    10000,         8,         0,    3.93,custom-tesseract-decoder,8e4f5ab5dde00fec74127eea39ea52d5a98ae6ccfc277b5d9be450f78acc1c45,"{""d"":5,""decoder"":""custom-tesseract-decoder""}",  
    10000,        10,         0,    5.74,tesseract-short-beam,bf696535d62a25720c3a0c624ec5624002efe3f6cb0468963eee702efb48abc1,"{""d"":5,""decoder"":""tesseract-short-beam""}",  
    10000,         5,         0,    1.27,tesseract,3f94c61f1503844df6cf0d200b74ac01bfbc5e29e70cedbfc2faad67047e7887,"{""d"":7,""decoder"":""tesseract""}",  
    10000,         4,         0,    25.0,tesseract-long-beam,4d510f0acf511e24a833a93c956b683346696d8086866fadc73063fb09014c23,"{""d"":7,""decoder"":""tesseract-long-beam""}",  
    10000,         1,         0,    18.6,tesseract-short-beam,75782ce4593022fcedad4c73104711f05c9c635db92869531f78da336945b121,"{""d"":7,""decoder"":""tesseract-short-beam""}",  
    10000,         4,         0,    11.6,custom-tesseract-decoder,48f256a28fff47c58af7bffdf98fdee1d41a721751ee965c5d3c5712ac795dc8,"{""d"":7,""decoder"":""custom-tesseract-decoder""}",  

This example runs simulations for a repetition code with different distances [3, 5, 7] with different Tesseract default decoders.

Sinter can also be used at the command line. Here is an example of this using Tesseract:

sinter collect \
    --circuits "example_circuit.stim" \
    --decoders tesseract \
    --custom_decoders_module_function "tesseract_decoder:make_tesseract_sinter_decoders_dict" \
    --max_shots 100_000 \
    --max_errors 100
    --processes auto \
    --save_resume_filepath "stats.csv" \

Sinter efficiently manages the execution of these tasks, and Tesseract is used for decoding. For more usage examples, see the tests in src/py/tesseract_sinter_compat_test.py.

Good Starting Points for Tesseract Configurations:

The Tesseract paper recommends two setup for starting your exploration with tesseract:

(1) Long-beam setup:

tesseract_config = tesseract.TesseractConfig(
    dem=dem,
    pqlimit=1_000_000,
    det_beam=20,
    beam_climbing=True,
    det_orders=tesseract_decoder.utils.build_det_orders(
        dem=dem,
        num_det_orders=21,
        method=tesseract_decoder.utils.DetOrder.DetIndex,
    ),
    no_revisit_dets=True,
)

(2) Short-beam setup:

tesseract_config = tesseract.TesseractConfig(
    dem=dem,
    pqlimit=200_000,
    det_beam=15,
    beam_climbing=True,
    det_orders=tesseract_decoder.utils.build_det_orders(
        dem=dem,
        num_det_orders=16,
        method=tesseract_decoder.utils.DetOrder.DetIndex,
    ),
    no_revisit_dets=True,
)

For det_order, you can use two other options of DetIndex and DetCoordinate as well. These values balance decoding speed and accuracy across the benchmarks reported in the paper and can be adjusted for specific use cases.

Help

We are committed to providing a friendly, safe, and welcoming environment for all. Please read and respect our Code of Conduct.

Citation

When publishing articles or otherwise writing about Tesseract Decoder, please cite the following:

@misc{beni2025tesseractdecoder,
    title={Tesseract: A Search-Based Decoder for Quantum Error Correction},
    author = {Aghababaie Beni, Laleh and Higgott, Oscar and Shutty, Noah},
    year={2025},
    eprint={2503.10988},
    archivePrefix={arXiv},
    primaryClass={quant-ph},
    doi = {10.48550/arXiv.2503.10988},
    url={https://arxiv.org/abs/2503.10988},
}

Contact

For any questions or concerns not addressed here, please email tesseract-decoder-dev@google.com.

Disclaimer

Tesseract Decoder is not an officially supported Google product. This project is not eligible for the Google Open Source Software Vulnerability Rewards Program.

Copyright 2025 Google LLC.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

tesseract_decoder-0.1.1.dev20260218025821-py313-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

Uploaded Python 3.13manylinux: glibc 2.39+ x86-64

tesseract_decoder-0.1.1.dev20260218025821-py313-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

Uploaded Python 3.13manylinux: glibc 2.35+ x86-64

tesseract_decoder-0.1.1.dev20260218025821-py313-none-macosx_11_0_arm64.whl (3.2 MB view details)

Uploaded Python 3.13macOS 11.0+ ARM64

tesseract_decoder-0.1.1.dev20260218025821-py312-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

Uploaded Python 3.12manylinux: glibc 2.39+ x86-64

tesseract_decoder-0.1.1.dev20260218025821-py312-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

Uploaded Python 3.12manylinux: glibc 2.35+ x86-64

tesseract_decoder-0.1.1.dev20260218025821-py312-none-macosx_11_0_arm64.whl (3.2 MB view details)

Uploaded Python 3.12macOS 11.0+ ARM64

tesseract_decoder-0.1.1.dev20260218025821-py311-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

Uploaded Python 3.11manylinux: glibc 2.39+ x86-64

tesseract_decoder-0.1.1.dev20260218025821-py311-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded Python 3.11manylinux: glibc 2.35+ x86-64

tesseract_decoder-0.1.1.dev20260218025821-py311-none-macosx_11_0_arm64.whl (3.2 MB view details)

Uploaded Python 3.11macOS 11.0+ ARM64

tesseract_decoder-0.1.1.dev20260218025821-py310-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

Uploaded Python 3.10manylinux: glibc 2.39+ x86-64

tesseract_decoder-0.1.1.dev20260218025821-py310-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded Python 3.10manylinux: glibc 2.35+ x86-64

tesseract_decoder-0.1.1.dev20260218025821-py310-none-macosx_11_0_arm64.whl (3.2 MB view details)

Uploaded Python 3.10macOS 11.0+ ARM64

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py313-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py313-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 56f691f9beddbf2405c5d7e309218de9a601173f27c5b16652030527967da40e
MD5 06951c0806c2641e8178b0c23b1081b4
BLAKE2b-256 ab47f4669cc36ce01bcfebc36c851d04ea8a718d59a7235611c25f2b1289dba0

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py313-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py313-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2fa7fbd3cf54339f19a0dda8a5a5bc76c45e0144f02780d1e7bcb6c7b3cf063e
MD5 bffa94e6029f7056e866135fa6335c2b
BLAKE2b-256 aa52a11811b845f506387a586f8e1d3e6cbed79830315dbd6f58fba0f24ed270

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py313-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py313-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 526d44e346f5da7b56956539f9712be05001a2f13ead64d166d2ad5de981fc05
MD5 5d3da9b79a53408ca3d2ad1f3777b652
BLAKE2b-256 8528e735a7dd8aa8470181188f2d66838fb45d8d560c8e1706ee99ad4a3c134d

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py312-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py312-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f558082bc45dff5456c7888072d598d07b76948186c1fa2a199ce33960d66c4d
MD5 cf570bcbea5c2f64ca430694b251567c
BLAKE2b-256 e957d941e77fa9b3ef7213a87dfdd9dcd3ff10d55d6ab6a1b9ede40b872ed45f

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py312-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py312-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 09dd14aa56b23da68e78abaaf323545d43017525c59a0fb53748fd5bf44a4bc1
MD5 5313d92c0c4f8ddc2e5e7d40c7a54f06
BLAKE2b-256 02fa95903e253656f377ca9ca196fbcac0f25f2263fd3e12b2a95d4fa9b9aa03

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py312-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py312-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b095812675dd9a64ab1da229bed4218e842a187a6f499ea83362879e60e60e22
MD5 0e6b173bbd5042854393c5b6bb8e7f85
BLAKE2b-256 f46aef9f2ebd3f7d5f0ceb45855cdb6b2e57ac99c915b982c03666c7ed04c2a2

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py311-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py311-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c5954058cf0fb7a87f24995a3796b825e0fe21eb33af8a2b5fde1b8872366e73
MD5 e8299741cfad43528f4d5ae6cf13bc82
BLAKE2b-256 bcd6c84e42063606591e57539af843c503b019b0a11ac54f5b42e109bd211775

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py311-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py311-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4971410ed31b5d98e99a73e87f48969e0fef743f1ab0ade2789103a2b81ab1d8
MD5 487b973666d6d401ba7a9d629315e864
BLAKE2b-256 04d806ce60fc9616f8674b02e1f7d93225f400d177870c7cb490ac1d72ab10b0

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py311-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py311-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ae9b1e9d9d9e450a0ab4c7e426092305fdcf14a867171d44879921dc1b2f86aa
MD5 31988b081dab8b7b25d69209050a76ed
BLAKE2b-256 31f4757fe01c1bd58b9b9fdde193d0a72b5b1d0c7faccf6bcf4f8ece6735cad0

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py310-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py310-none-manylinux_2_39_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d0253af62a8d09ed060ee962642e8be631d983f5471ebe8d8b1a3ce7cfc31867
MD5 041b0689c75c048f430d70fb84453ad1
BLAKE2b-256 34b36d9372d5886c98e1c6553efbb1b0ffc15b02f282bf30aa053dbf0a307191

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py310-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py310-none-manylinux_2_35_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5b1a7cd4193b118af1f02fe36cde9517e59950cee168b4c77bda5c6caa545161
MD5 69aec5f31c2687f5b9cbe26799d91522
BLAKE2b-256 6a06e2310bef59d2db0d0d01b3cd89d2884ff38e8db91afc0ff2adb7e13c5960

See more details on using hashes here.

File details

Details for the file tesseract_decoder-0.1.1.dev20260218025821-py310-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tesseract_decoder-0.1.1.dev20260218025821-py310-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 059ecba87ffde04501c2c49336f5fb3bdbbd7db55715f2f446a30634ebc9a1d2
MD5 25889e090609c77ad8288c15a79fb8fd
BLAKE2b-256 4d088e5b46e3bc6e8909ecf00bed75b0685aabbca40b2d5ff34c1cbd129117c6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page