Self-hosted error tracking in 2026: revisit Sentry, GlitchTip and Bugsink before you ship another stack trace

Picture a diagnostic lab chain headquartered in Mysuru, with collection centres in Mandya, Hassan, Madikeri, Hunsur and Chamarajanagar (an invented example, not a real client). Patients book home sample collection through a Python booking API, pay online, and get an SMS with a link to a report portal written in JavaScript. Errors today live in application logs. When the payment gateway had a bad hour, the logs filled with thousands of near-identical lines, and the first person to notice was a patient at the Hassan counter.

The team is three developers and one person who looks after the servers. They want errors grouped, with a stack trace and the release that shipped it. One rule cannot break: patient phone numbers, report links and payment details stay on servers the lab controls. So a hosted service is out, and three proposals arrive. A developer who used it at a previous job wants Sentry self-hosted. The ops person, who already runs PostgreSQL, wants GlitchTip. The youngest developer found Bugsink and likes how little it needs to run.

This post compares those three as they stand on 19 October 2026: licences, governance, footprint, grouping, privacy defaults, rate limits, retention, source maps, operations and security records. Hosted plans, APM, replay and profiling are out of scope. The question is narrow: what happens to one exception on its way from your code to an issue page.

Facts come from GitHub and GitLab releases and LICENSE history, official docs and changelogs, CVE records, GitHub advisories and OSV, and a drill that sent the same events from sentry-sdk 2.72.0 (Python) and @sentry/node to Bugsink 2.6.1 and GlitchTip 6.2.6 on one shared box. Sentry self-hosted was not run (reasons in the drill section). It is not a benchmark, and nothing here is legal advice.

The short version

  • An error tracker is a grouping and privacy decision before it is a dashboard. In the drill, the same 20 Python events became 11 issues in Bugsink and 17 in GlitchTip, because Bugsink normalises numbers, UUIDs and dates in the message before grouping and GlitchTip hashes the title as it is.
  • The SDK decides most of what leaves your process, and its defaults are not a privacy policy. With sentry-sdk 2.72.0 defaults, password was filtered but a local api_token, a card number in a string, an email and a phone number were all sent, and a WSGI environ local carried the raw cookie and bearer token.
  • Sentry self-hosted 26.10.0 (16 October 2026) is the full product under the Functional Source License (FSL-1.1, Apache 2.0 after two years). Its compose file defines 53 services, and the installer wants 4 CPU cores and about 14 GB of RAM (2 cores and 7 GB in errors-only mode). Five Sentry CVEs were published in 2026, three of them about SAML SSO.
  • GlitchTip 6.2.6 (tag of 8 August 2026) is MIT, Django on PostgreSQL, with Valkey optional and a recommended 512 MB of RAM. It added opt-in server-side PII scrubbing in 6.2.1. Its throttle is a percentage, and a per-key rate limit I set was not enforced in my run.
  • Bugsink 2.6.1 (25 September 2026) is a single Python application on SQLite, MySQL or PostgreSQL, under the PolyForm Shield 1.0.0 licence, which is source-available, not open source. Count-based rate limits and “smart” retention worked as documented. Its GitHub repository lists 13 advisories, several reachable with nothing more than a DSN.
  • Source maps: Bugsink applied an uploaded map to an event that arrived before the upload; GlitchTip did not, and only a re-sent event was resolved. Upload maps before you deploy.

Where things stand on 19 October 2026

Dates are GitHub release published_at or GitLab tag commit dates, converted to IST (UTC+5:30). Licences are from the LICENSE files in each repository.

Project

Release

Date (IST)

Notes

Licence

Sentry (getsentry/sentry)

26.10.0

16 October 2026, 6:25 AM

Monthly calendar versions

FSL-1.1-Apache-2.0

Sentry self-hosted (getsentry/self-hosted)

26.10.0

16 October 2026, 6:47 AM

Docker Compose install; 18 releases in 2026

FSL-1.1-Apache-2.0

sentry-python

2.72.0

12 October 2026, 6:38 PM

SDK used in the drill

MIT

GlitchTip backend (glitchtip/glitchtip-backend)

v6.2.6

8 August 2026, 7:24 AM (tag commit)

Latest backend tag; version run in the drill

MIT

GlitchTip frontend

v7.0.0rc2

7 October 2026, 7:07 PM

Release candidate, frontend only

MIT

Bugsink (bugsink/bugsink)

2.6.1

25 September 2026, 2:12 PM

Latest; 21 GitHub releases in 2026

PolyForm Shield 1.0.0 (with exceptions)

Attention on 19 October 2026: getsentry/sentry about 45,599 GitHub stars and 2,326 open issues and pull requests; getsentry/self-hosted 9,616 stars and 140 open; Bugsink 2,134 stars and 138 open; GlitchTip backend 361 stars on GitLab, with its last activity on 16 October. Stars show interest, not suitability for your lab.

Timeline

Date (IST)

Event

August 2010

getsentry/sentry repository created on GitHub; BSD 3-Clause until 2019

7 November 2019

Sentry switches its LICENSE to the Business Source License 1.1

21 November 2019

GlitchTip backend repository created on GitLab

8 May 2020

GlitchTip beta announced

April 2022

GlitchTip 1.12 adds JavaScript source maps for issues

17 November 2023

Sentry relicenses under FSL-1.0-Apache-2.0; self-hosted follows the next day

28 February 2024

Both Sentry repositories move to FSL-1.1

15 May 2024

First LICENSE file in the Bugsink repository

15 January 2025

Bugsink changes its licence to PolyForm Shield 1.0.0

13 November 2025

GlitchTip 5.2 adds a PostgreSQL-only mode

3 February 2026

GlitchTip 6

21 February 2026

CVE-2026-27197 (Sentry SAML account takeover) published

22 June 2026

GlitchTip 6.2 announced

8 August 2026

GlitchTip v6.2.6 tagged

25 September 2026

Bugsink 2.6.1

15 October 2026

CVE-2026-102899 (Sentry SAML identity linking) published

16 October 2026

Sentry and self-hosted 26.10.0

First question: what should become one issue, and what may leave the process?

“We need error tracking” sounds like a dashboard request. It is really three decisions, and the tools differ at each one:

  1. Grouping rules. Which events become one issue. If “slot 2 is full for booking 3ae9…” and “slot 5 is full for booking 8aa2…” are two issues, your alert channel will be noisy and nobody will trust it. If a payment timeout and a refused connection are one issue, you may miss that the gateway changed behaviour.
  2. Capture rules. What leaves the process. Stack frames with local variables, request headers, query strings, the user you attached, breadcrumbs. Every error report is a small copy of application data, and the SDK decides most of it before the server sees anything.
  3. Keeping rules. How much arrives and how long it stays: rate limits when something loops, retention by days or by count, and what a backup brings back.

Write the promise in one sentence and get it signed before you install anything:

When [a known failure, such as the payment gateway timing out] happens [N times in a minute], the on-call developer sees [one issue with one alert], with [release, environment and stack trace], and the report never contains [patient phone, report link, card or token]. We keep [N events or N days] and can lose [the event history, or not] in a restore.

The dashboard comes last; every tool here has one.

What each tool actually is

Sentry self-hosted 26.10.0

Sentry is the original, and its SDKs and event format are what the other two accept. Until 2019 it was BSD 3-Clause. A commit on 7 November 2019 (IST) moved it to the Business Source License 1.1; the relicensing post argued that permissive licences such as BSD and Apache-2.0 no longer fitted how the software was used. On 17 November 2023 Sentry moved to its own Functional Source License, upgraded to FSL-1.1 on 28 February 2024. FSL allows use, modification and redistribution for any purpose except a “Competing Use”, and each version becomes Apache 2.0 two years after release. Sentry’s own docs call this Fair Source and say plainly that it is not under the OSI umbrella. The steward is Functional Software, Inc. (dba Sentry).

Self-hosted is a separate repository, getsentry/self-hosted, with Docker Compose files and an install.sh. By default it runs the full feature set: errors, issues and alerts, plus traces, profiles, replays, crons and user feedback. The docker-compose.yml I fetched on 19 October 2026 defines 53 services, among them PostgreSQL behind pgbouncer, Kafka, ClickHouse, Redis, memcached, SeaweedFS, Relay, Snuba consumers, Symbolicator, task workers and nginx. The installer checks for 4 CPU cores and 14,000 MB of RAM, or 2 cores and 7,000 MB with the errors-only profile; the docs list 4 cores, 16 GB RAM plus 16 GB swap and 20 GB of free disk, and recommend 32 GB.

Releases are monthly calendar versions (26.10.0 is October 2026), and the upgrade notes matter. You must stop at each hard stop to pick up database changes; the list on 19 October included 23.11.0, 24.8.0, 25.5.1, 26.5.0 and 26.7.0. There is also a list of versions to avoid, which included 25.6.0, 25.9.0, 25.12.0 and 26.3.0 because of migration and storage problems. The backup page is honest about scope: the built-in JSON backup covers “low-volume” data such as users, organisations and configuration, and excludes events and issues.

GlitchTip 6.2.6

GlitchTip is an MIT-licensed tracker by Burke Software and Consulting, with a Django backend (since 2019) and an Angular frontend. It accepts Sentry SDKs, so you change the DSN and keep your code. Its 2021 post on sustainable open source explains the model: Burke Software had funded open source through mostly unrelated contract work, and GlitchTip asks self-hosters who do not need support for a donation. Version 5.2 (November 2025) added a PostgreSQL-only mode, and 6.x moved more work into Rust: an ingest path behind GLITCHTIP_RUST_INGEST (off by default), which since 6.2.3 also runs without Valkey.

The install docs recommend 512 MB of RAM (256 MB as a minimum in all-in-one mode), x86 or arm64, PostgreSQL, and Valkey or Redis 7+ as optional. Beyond errors it has uptime monitoring, basic performance data, logs (6.2.0 added an OTLP/HTTP logs endpoint), an MCP server, and since 6.1 cold storage of older events as Parquet on S3-compatible storage. Retention is by days: GLITCHTIP_RETENTION_DAYS defaults to 90, with events kept 30 days in PostgreSQL before archival.

Grouping is simple and readable in the source: an MD5 of the title, the culprit and the event type, unless the event carries a fingerprint (which may include {{ default }}). There is no normalisation of numbers or IDs, which the drill shows. Version 6.2.1 added optional server-side PII scrubbing at ingest, off unless a project’s scrub_config enables it: key-name matching for secrets and value patterns for Luhn-valid card numbers and PEM keys, with email addresses opt-in. Rate control has two parts: event_throttle_rate, a percentage of events to reject, and per-key rate_limit_count and rate_limit_window fields. In 6.2.6 I found the key fields used in the API schema but not in the ingest code, and the drill agreed.

The CHANGELOG is unusually detailed. On 19 October the newest backend tag was v6.2.6 (8 August 2026), master had commits on 13 October, and the frontend had 7.0.0 release candidates.

Bugsink 2.6.1

Bugsink is from Bugsink B.V. (its site says made and hosted in the EU), on GitHub since August 2024. It is deliberately narrow: error tracking only (“without the overhead of full APM”), Sentry SDK compatible, a single Python application (a web server plus Snappea, its own background-task process), and SQLite by default, with MySQL or PostgreSQL as options. Its “built to self-host” page argues that scrubbing is a fragile answer to sensitive data in error reports, and that keeping the data on your own servers is the better one.

The licence needs reading. The root LICENSE puts most of the code under the PolyForm Shield License 1.0.0 (since 15 January 2025), with exceptions: a sentry directory under BSD 3-Clause, icons under MIT, one file under the PSF licence, and an ee/ directory under its own licence if it exists. PolyForm Shield allows any use except providing a product that competes with the licensor: source-available, not OSI open source. The site lists self-hosting as free with unlimited users and all features, and sells support and a managed service.

Grouping is documented and specific: before hashing, Bugsink replaces emails, URLs, hostnames, IP addresses, UUIDs, hashes, hex values, integers, floats, dates, times, durations and quoted values in the message with placeholders such as <int> and <uuid>. The title still shows the original text, and an issue page has a Grouping tab showing the key. Rate limits are counts: 1,000 events per project and 1,000 per installation per 5 minutes, and 5,000 per hour, by default. Retention is by count (10,000 events per project by default) with an algorithm that keeps a spread of events rather than only the newest. PHONEHOME is on by default; I turned it off.

Comparison tables

Cells without a primary source say “Not documented”.

Licence, governance and maintainer health

Sentry self-hosted

GlitchTip

Bugsink

Licence

FSL-1.1-Apache-2.0 (Apache 2.0 after two years per version)

MIT

PolyForm Shield 1.0.0, with BSD, MIT and PSF exceptions

OSI open source

No (Fair Source)

Yes

No (source-available)

Licence changes

BSD to BSL 1.1 (2019), to FSL (2023), FSL-1.1 (2024)

None found

Placeholder (2024), PolyForm Shield (2025)

Steward

Functional Software, Inc. (Sentry)

Burke Software and Consulting

Bugsink B.V.

Commercial offer

Sentry SaaS

Hosted GlitchTip

Managed hosting, paid support

Release rhythm

Monthly calendar versions

Frequent patch tags; 6.2.6 latest

21 releases in 2026

Foundation

None

None

None

Architecture and footprint

Sentry self-hosted

GlitchTip

Bugsink

Stack

Python, Rust and others in 53 compose services

Django, Rust ingest, Angular frontend

Django web process plus Snappea task process

Storage

PostgreSQL, ClickHouse, Kafka, Redis, SeaweedFS

PostgreSQL; optional Valkey; optional Parquet cold storage

SQLite (default), MySQL or PostgreSQL

Minimum host

4 cores, about 14 GB RAM (installer check); errors-only 2 cores, about 7 GB

512 MB recommended, 256 MB minimum all-in-one

Not documented as a number

Supported install

Docker Compose (Helm is community only)

Docker Compose, Helm chart, PaaS templates

Docker, Docker Compose, virtualenv

In the drill

Not run

About 35 + 171 MiB RSS (granian) plus PostgreSQL 18

About 25 + 82 MiB RSS (gunicorn) on SQLite

Features that matter for errors

Sentry self-hosted 26.10

GlitchTip 6.2.6

Bugsink 2.6.1

Accepts Sentry SDKs

Native

Yes

Yes

Default grouping

Not documented in sources read

MD5 of title, culprit and type

Normalised message plus type

Fingerprint override

Yes

Yes, with {{ default }}

Yes

Server-side scrubbing

Not documented in sources read

Opt-in per project since 6.2.1

Not documented; its docs argue for keeping data on your own servers instead

Rate control

Not documented for self-hosted in sources read

Percentage throttle; key limits stored

Counts per 5 minutes, hour and month

Retention

Not documented in sources read

90 days by default; hot 30 days

10,000 events per project, smart retention

Source maps

Yes (sentry-cli is Sentry’s own uploader)

Yes, applied at ingest

Yes, applied when viewed

Beyond errors

Traces, profiles, replays, crons, feedback

Uptime, logs, basic performance, MCP

Errors only

Operations

Sentry self-hosted

GlitchTip

Bugsink

Upgrades

Monthly; hard stops; versions to avoid

Read the CHANGELOG; 6.2.5 rebuilt the uptime check table and dropped its history

Documented upgrade page

Backup

JSON backup of low-volume data; events need volume backups

PostgreSQL backup (plus object storage if cold storage is on)

SQLite file or your database’s backup

Moving parts to monitor

Kafka, ClickHouse, consumers, workers

PostgreSQL, web, worker, optional Valkey

Web and Snappea processes, and the database

Telemetry default

Not documented in sources read

Not documented

PHONEHOME on

Security

Sentry self-hosted

GlitchTip

Bugsink

CVEs published in 2026

5 (three SAML SSO)

None found

7

Advisory channel

GitHub advisories (21 for getsentry/sentry)

CHANGELOG “Security:” entries

GitHub advisories (13)

SSO

SAML (per the 2026 advisories)

OpenID Connect; per-organisation SSO since 6.2.3

Not documented in sources read

Outbound request guard

Not documented in sources read

SSRF checks; private IPs blocked unless allowed

Webhook allow and deny lists; non-global address protection

Worked example for the Mysuru scenario

The Mysuru team (invented) used their own booking API errors from a week of logs, then ran the drill below against both candidate tools.

Step 1. List the failures you already know: slot conflicts, missing fields, gateway timeouts and refusals, SMS rejections, a portal crash. Each should map to one issue you can name.

Step 2. Decide grouping before choosing a tool. Slot messages carry a booking UUID and a time. On Bugsink they collapsed into one issue; on GlitchTip each was its own issue. On either tool, set a fingerprint where you know better than the default, for example one issue for “payment gateway down” whether it times out or refuses.

Step 3. Write the capture policy as code. The SDK default sent phone numbers, a token and a card number from local variables. The fix is a before_send hook and switching off local variables in the services that touch patient data:

import re, sentry_sdk
PHONE = re.compile(r"\+?91[ -]?\d{5}[ -]?\d{5}")

def scrub(event, hint):
    for exc in (event.get("exception") or {}).get("values", []):
        if exc.get("value"):
            exc["value"] = PHONE.sub("[phone]", exc["value"])
    req = event.get("request") or {}
    for k, v in list((req.get("headers") or {}).items()):
        if isinstance(v, str) and PHONE.search(v):
            req["headers"][k] = PHONE.sub("[phone]", v)
    if req.get("query_string"):
        req["query_string"] = re.sub(r"token=[^&]*", "token=[Filtered]", req["query_string"])
    event.pop("user", None)          # not in the drill run; keep only an opaque id if needed
    return event

sentry_sdk.init(dsn=DSN, release="booking-api@2026.10.19", environment="production",
                send_default_pii=False, include_local_variables=False,
                before_send=scrub, traces_sample_rate=0)

The drill version did not drop user, and the attached email still arrived. Test the hook with real-looking data, as you would test any other code.

Step 4. Set limits for the bad hour. On Bugsink, set MAX_EVENTS_PER_PROJECT_PER_5_MINUTES to what one person can read. On GlitchTip, do not rely on a DSN key limit in 6.2.6; use the throttle percentage or SDK sampling (sample_rate) for noisy services.

Step 5. Upload source maps in the build, before deploy. Inject debug IDs with sentry-cli sourcemaps inject, upload, then release. This matters most on GlitchTip, which resolves frames at ingest.

Security and hygiene

On 19 October 2026 the GitHub advisories API returned 21 published advisories for getsentry/sentry, none for getsentry/self-hosted, two for getsentry/relay, two for sentry-python and 13 for bugsink/bugsink. GlitchTip is on GitLab; an NVD keyword search for it returned no results. Each CVE ID below was checked in the CVE API (cveawg.mitre.org).

Sentry (2026 CVEs, all from the GitHub CNA):

  • CVE-2026-27197 (21 February 2026, 10:05 AM IST; CVSS 3.1 9.1): SAML SSO flaw allowing account takeover with a malicious identity provider and another organisation on the same instance. Affected 21.12.0 to before 26.2.0.
  • CVE-2026-42354 (9 May 2026, 4:28 AM IST; CVSS 3.1 9.1): another SAML SSO account takeover. Affected 21.12.0 to before 26.4.1.
  • CVE-2026-52794 (25 June 2026, 2:56 AM IST; CVSS 3.1 7.5): ReDoS in the event ingestion pipeline through attacker-controlled fields. Affected 24.4.0 to before 26.5.2.
  • CVE-2026-83803 (22 September 2026, 9:54 PM IST; CVSS 4.0 7.7): unsafe pickle deserialisation in the relocation import feature, for authenticated users where relocation is enabled. Affected 23.11.0 to before 26.7.0.
  • CVE-2026-102899 (15 October 2026, 12:27 AM IST; CVSS 4.0 7.6): SAML identity-linking flow abuse through social engineering. Affected 26.5.0 to before 26.7.2.
  • GHSA-rrcx-889m-5jj5 (critical, 17 August 2026, no CVE ID listed): SAML SSO allowing unauthorised member addition or identity linking, patched in 26.8.0.

Bugsink (GitHub CNA):

  • CVE-2025-54433 (30 July 2025; CVSS 4.0 7.2): path traversal through event_id at ingestion; fixed in 1.4.3, 1.5.5, 1.6.4 and 1.7.4.
  • CVE-2025-64508 and CVE-2025-64509 (November 2025; CVSS 3.1 7.5 each): unauthenticated denial of service through Brotli-compressed envelopes, needing only a DSN; fixed in 2.0.5 and 2.0.6.
  • CVE-2026-27614 (25 February 2026; CVSS 3.1 9.3): stored XSS through the Pygments fallback in stack trace rendering, by anyone who can submit events; fixed in 2.0.13.
  • CVE-2026-40162 (10 April 2026; CVSS 3.1 7.1): authenticated arbitrary file write in artifact bundle assembly in 2.1.0; fixed in 2.1.1.
  • CVE-2026-44502 (26 May 2026; 4.3): webhook URL validation bypass (SSRF); fixed in 2.1.3.
  • CVE-2026-47715, CVE-2026-47716 and CVE-2026-47728 (26 May 2026; 3.1, 3.1 and 4.3): project-boundary checks missing on event views, bulk actions and source map lookup; fixed in 2.2.0.
  • CVE-2026-53954 (15 September 2026; 4.3): denial of service through very large tag sets with a valid DSN; fixed in 2.2.2.
  • GitHub also lists GHSA-w589-2ffr-2prv (webhook SSRF through DNS rebinding, fixed in 2.4.0) with CVE-2026-76908, but the CVE API returned “record does not exist” for that ID on 19 October 2026. Two more, about link lifetimes and NAT64 webhook destinations, were fixed in 2.5.1 without CVE IDs.

GlitchTip records security fixes in its CHANGELOG: 6.2.3 fixed an SSRF bypass through redirects and DNS rebinding in uptime monitors, webhooks and the project importer, and 6.2.5 capped artifact bundle extraction after a zip-bomb style issue.

Habits that matter more than counting CVEs:

  • Treat the DSN as public. It sits in every browser bundle. Several Bugsink advisories and a Sentry advisory title about public DSNs show that anyone with it can send you crafted events, so patch the ingest path quickly.
  • Patch SSO-enabled Sentry monthly. Four SAML issues in one year is a pattern, not bad luck.
  • Scrub in the SDK, and test the scrubber. Server-side scrubbing (GlitchTip) is a second line, not the first.
  • Keep the UI private. Ingest may need to be public for browser apps; the issue pages, with patient data in them, do not.
  • Guard outbound requests. Webhooks and uptime checks are SSRF paths in all three; keep private-address blocking on.
  • Decide phone-home on purpose. Bugsink’s PHONEHOME is on by default.

Decision guide

Situation

Lean towards

Why

You want everything Sentry SaaS has, on your hardware, and have 16 to 32 GB to spare

Sentry self-hosted

Full product; same team as the SDKs

Small team, errors only, one server, least to operate

Bugsink

Single application, SQLite, count-based limits and retention

Licence must be OSI open source

GlitchTip

MIT; Sentry is FSL and Bugsink is PolyForm Shield

You already run PostgreSQL and want uptime checks and logs too

GlitchTip

PostgreSQL-centred, uptime and OTLP logs built in

Noisy messages with IDs and numbers

Bugsink, or fingerprints elsewhere

Message normalisation before grouping

SAML SSO with many organisations on one instance

Sentry with fast patching, or test SSO carefully on the others

Richest SSO, but four SAML advisories in 2026

You plan to offer error tracking to customers as a service

Read every licence with a lawyer

FSL and PolyForm Shield both restrict competing use

Mysuru (invented) pick. The team chose Bugsink 2.6.1 on a small VM with PostgreSQL, a private UI and only the ingest path exposed for the portal. It is errors-only, which is what they asked for; grouping kept the slot-conflict noise to one issue; count limits and retention are easy to reason about; and source maps resolved even when an upload came late. They checked that PolyForm Shield permits internal use, because they are not building an error tracking product. Their before_send hook and include_local_variables=False are tested in CI with fake patient data. GlitchTip stayed as the fallback if they later want an MIT licence, uptime checks or logs in the same tool. Sentry self-hosted was ruled out on footprint: 53 services and a 16 GB host to watch, for three developers.

Checklist

  1. Write the one-sentence promise: grouping, capture and keeping rules.
  2. Replay a week of real errors and count the issues each tool creates.
  3. Set fingerprints for the failures you already understand.
  4. Turn off local variables where patient or payment data lives, or scrub them in before_send.
  5. Test the scrubber with fake phone numbers, tokens, card numbers and emails.
  6. Set rate limits or sampling for the “bad hour”, and test that the SDK backs off on 429.
  7. Decide retention by days or by count, and size the disk for it.
  8. Upload source maps with debug IDs before you deploy.
  9. Keep the UI private, the DSN rate limited, and outbound webhooks restricted.
  10. Practise a restore and note what it does not bring back.

Common mistakes

  1. Choosing by dashboard screenshots instead of by grouping behaviour.
  2. Assuming send_default_pii=False means no personal data is sent.
  3. Leaving local variables on in code that handles patient, payment or token data.
  4. Trusting a server-side scrubber to catch everything; in the drill it missed a bearer token.
  5. Treating the DSN as a secret.
  6. Setting a GlitchTip key rate limit and assuming it is enforced.
  7. Uploading source maps after the deploy and wondering why the first errors are minified.
  8. Upgrading Sentry self-hosted across a hard stop, or onto a version on the avoid list.
  9. Calling FSL or PolyForm Shield software “open source” in a procurement note.
  10. Forgetting that the error tracker itself needs patching, monitoring and backups.

A drill I ran on 19 October 2026

Shared Linux VM (Debian 13, 8 vCPU, 15 GiB RAM, other workloads running), no Docker. The main runs were between about 6:29 AM and 6:37 AM IST, with one re-sent JavaScript event and a scrubber check at about 10:25 AM IST. One box and a handful of invented events, so nothing here is a speed claim.

Setup:

  • Bugsink 2.6.1 wheel (SHA-256 matched PyPI), in a virtualenv with gunicorn on 127.0.0.1, SQLite, the local configuration template (tasks run inline, no separate Snappea process), PHONEHOME off, and MAX_EVENTS_PER_PROJECT_PER_5_MINUTES lowered to 30 to see a 429.
  • GlitchTip 6.2.6 backend from the GitLab tag (commit d3039088), run with granian in all-in-one mode on PostgreSQL 18.6, no Valkey (database cache and queue), the default Python ingest path (GLITCHTIP_RUST_INGEST defaults to off), 127.0.0.1 only. Migrations applied 127 steps.
  • Sentry self-hosted was not run: it needs Docker, which this box does not have, and a host with about 14 GB of RAM free for the installer check. Its facts above come from the repository and docs.
  • Clients: sentry-sdk 2.72.0 (Python 3.13, wheel SHA-256 matched PyPI) for an invented booking module, and @sentry/node 11.8.0 with sentry-cli 3.8.0 for a minified report script. SDK defaults printed: include_local_variables True, send_default_pii not set (off), max_request_body_size “medium”.

Grouping. The same 20 events went to both servers:

Events sent

Bugsink 2.6.1

GlitchTip 6.2.6

5 “slot N is full for booking (uuid) at 10:0N” from book_slot, 2 more from cancel_slot

1 issue, key ValueError: slot <int> is full for booking <uuid> at <date>

7 issues

KeyError for patient_phone and for patient_email on the same line

2 issues

2 issues

Timeout and refused, both with fingerprint payment-gateway-down

1 issue

1 issue

Same TimeoutError from production and from staging

1 issue

1 issue

One refused connection without fingerprint

1 issue

1 issue

SMS error with the phone in the message, sent twice

1 issue (digits became <int>)

1 issue

Four other one-off events from the privacy runs

4 issues

4 issues

Total, 20 events

11 issues

17 issues

Two surprises. Bugsink merged book_slot and cancel_slot into one issue because the normalised message and type matched, though the functions differ; that is documented behaviour, but may not be what you want. And neither tool split production from staging; environment is a filter, not a grouping key.

What left the process. The same invented function held a password, an API token, a card number, an email and a phone number in local variables, and a WSGI request carried a cookie, a bearer token, a phone header and ?token= in the query string. What was stored:

Data

SDK defaults

send_default_pii=True

before_send plus no local variables

GlitchTip server-side scrub on

Local password

[Filtered]

[Filtered]

No variables sent

[Filtered]

Local api_token

Sent

Sent

No variables sent

[Filtered]

Card number inside a string

Sent

Sent

No variables sent

[Filtered]

Phone in the exception message

Sent

Sent

[phone]

Sent

Cookie and Authorization headers

[Filtered]

[Filtered]

[Filtered]

[Filtered]

X-Patient-Phone header

Sent

Sent

[phone]

Sent

Raw cookie and bearer token in the environ local

Sent

Sent

No variables sent

Cookie filtered, bearer token sent

token= in the query string

Sent

Sent

[Filtered]

[Filtered]

Client IP (REMOTE_ADDR) in request data

Not sent

Sent

Not sent

Sent (scenario had PII on)

Email set with set_user

Sent

Sent

Sent

[Filtered] (emails opted in)

The SDK columns matched on both servers, because the SDK does the work. My first before_send handled only the message and frame variables and missed the phone header; the worked example version fixed that. A scrubber is code, and needs tests.

Rate limits and retention.

Check

Bugsink 2.6.1

GlitchTip 6.2.6

40 events in under a second

30 accepted, then 10 rejected with 429 and X-Sentry-Rate-Limits: 60::key, ...

With a key limit of 10 per 60 s: all 40 accepted

Project throttle

Not applicable

event_throttle_rate 50: 10 of 40 accepted, 429 with Retry-After: 162

Retention

Project limit 20: 30 events digested, 20 kept, spread across the sequence (1 to 6, then about every other, up to 30)

90-day default shown at start; not exercised in a short drill

Source maps. A minified report.min.js threw TypeError: Cannot read properties of undefined (reading 'toUpperCase'). Debug IDs were injected with sentry-cli sourcemaps inject and the bundle was uploaded to both tools, about seven seconds after the event had already arrived. Bugsink showed the frame as src/report.js line 3, const unit = result.unit.toUpperCase();, for that earlier event, because it applies maps when the event is viewed. GlitchTip kept the earlier event minified (report.min.js line 3, column 129, function e). An event re-sent at about 10:25 AM IST, after the upload, was resolved to src/report.js line 3 in formatResult.

Footprint after the drill. Bugsink gunicorn, about 25 and 82 MiB RSS for its two processes, with a 968 KB SQLite file. GlitchTip granian, about 35 and 171 MiB, plus PostgreSQL, where the GlitchTip database was 21 MB with 291 tables and partitions. Single readings on a shared box.

What this box could not test: Sentry self-hosted at all, any tool under real load or concurrency, upgrades between versions, backups and restores, SSO, alert delivery by email or chat, native crash reports, GlitchTip’s Rust ingest path and cold storage, and Bugsink on PostgreSQL or MySQL. All drill servers (Bugsink gunicorn, GlitchTip granian and the PostgreSQL 18 instance) were stopped at the end. Scripts, logs and results are under drill48/.

Unlearn

  • Unlearn that an error tracker is a dashboard you install.
  • Unlearn that “PII off” in the SDK means no personal data leaves.
  • Unlearn that a DSN is a secret.
  • Unlearn that “self-hosted” and “open source” mean the same licence.
  • Unlearn that every tool groups the same events the same way.

Re-learn

  • Re-learn your own failures, and name the issue each should become.
  • Re-learn the three rule sets: grouping, capture and keeping.
  • Re-learn the SDK options you never set: local variables, before_send, sampling.
  • Re-learn the build order: inject, upload, then deploy.
  • Re-learn the licence and the advisory feed of the tool you run, release by release.

Closing

Self-hosted error tracking in 2026 is less about features and more about rules you can explain to a patient or an auditor. Sentry self-hosted 26.10 is the full product under the FSL, with the footprint and upgrade discipline to match. GlitchTip 6.2.6 is MIT, light and PostgreSQL-centred. Bugsink 2.6.1 is a single application with careful grouping and count-based limits, under a source-available licence. In the posts on log storage and distributed tracing, the question was how much telemetry to keep. Here it is what one exception should become and what it should carry. Learn the three rule sets. Unlearn “PII off” as a policy. Re-learn your own failures. Practise with fake patient data. Apply it before you ship another stack trace.

Sources

Sentry

GlitchTip

Bugsink

Security records

Internal

comments powered by Disqus

Releted Posts

Self-hosted search in 2026: revisit Meilisearch, Typesense and Manticore Search before you add another search box

Picture an electrical and hardware distributor headquartered in Vadodara, with warehouses in Anand, Bharuch, Godhra, Rajkot and Surat (an invented example, not a real client).

Read more

MongoDB alternatives in 2026: revisit Percona Server for MongoDB, FerretDB and DocumentDB before you migrate another collection

Picture a diagnostic lab chain headquartered in Guwahati, with collection centres in Shillong, Jorhat, Silchar, Dibrugarh and Tezpur (an invented example, not a real client).

Read more

Load testing in 2026: revisit Grafana k6, Locust and Gatling before you run another performance test

Picture a company in Lucknow that hosts exam results and admit cards for several state boards and universities across Uttar Pradesh and Bihar (an invented example, not a real client).

Read more