Fehler, die man nur im Betrieb findet
Vier Vorfälle aus laufenden Webprojekten — alle bestanden jede Abnahme, alle richteten über Wochen Schaden an, bevor sie auffielen. Aufgeschrieben, weil sie sich wiederholen.
Software ist selten entweder heil oder kaputt. Häufiger ist sie teilweise kaputt — und zwar an einer Stelle, die keine Prüfung abdeckt. Die folgenden vier Fälle stammen aus Projekten, die wir selbst betreiben. Sie haben eines gemeinsam: Von außen sah alles in Ordnung aus.
Die Seite lädt, aber nichts funktioniert
Ein Nuxt-Projekt lieferte 44 Stunden lang auf jede Anfrage sauberes HTML mit Status 200. Gleichzeitig gaben sämtliche JavaScript-Dateien Serverfehler zurück. Ergebnis: Die Seite war lesbar, aber nicht bedienbar — keine Interaktion, keine Messung, kein Formular.
Ursache war ein Verweis, den der Build-Vorgang anlegen muss und in diesem Fall nicht angelegt hatte. Serverseitiges Rendern brauchte ihn nicht, das Ausliefern der Skriptdateien schon.
Warum es niemand merkte: Jede Überwachung prüft die Startseite. Die antwortete durchgehend korrekt. Erst als die Besucherzahlen drei Tage in Folge auf null standen und wir der Messung nachgingen, fiel der eigentliche Ausfall auf.
Was wir geändert haben: Die Überwachung prüft jetzt zusätzlich eine ausgelieferte Skriptdatei auf Status und Inhaltstyp. Und der fehlende Verweis wird nach jedem Build automatisch gesetzt, statt sich auf Disziplin zu verlassen.
Tausend Seiten, die niemand wollte
Ein Portal erzeugte aus einer Datenbank mehrere tausend Detailseiten — automatisch, korrekt, vollständig verlinkt. Jede einzelne enthielt rund 650 Zeichen Text, größtenteils Navigation. Zwei zufällig gewählte Seiten stimmten zu 69 Prozent im Wortlaut überein.
Suchmaschinen bewerteten das nicht Seite für Seite, sondern als Eigenschaft der gesamten Domain. Bei einem anderen Projekt derselben Bauart brachen die Impressionen innerhalb von zwei Wochen um 96 Prozent ein — nicht auf den neuen Seiten, sondern auf allen.
Der Denkfehler: Aus „wir haben Daten für 7.000 Seiten“ folgt nicht „7.000 Seiten sind sinnvoll“. Eine Seite rechtfertigt ihre Existenz durch eine Frage, die jemand stellt — nicht durch einen Datensatz, der vorliegt.
Was wir geändert haben: Die Massenseiten stehen auf „nicht indexieren“ und sind aus der Sitemap entfernt. Sie bleiben für Besucher und interne Verweise erreichbar. Zurück in den Index kommen sie erst, wenn sie eigenständigen Inhalt tragen.
Ein Tag zu viel, tausendfach
Ein Veranstaltungskalender zeigte bei mehrtägigen Terminen durchgehend einen Tag zu lang an. Die Ursache lag im Kalenderformat selbst: Bei ganztägigen Terminen ist das Enddatum dort ausschließend gemeint — ein Fest vom 31. Juli bis 2. August wird als „Ende: 3. August“ übertragen.
Dazu kam eine Zeitzonenfalle: Datumsangaben ohne Uhrzeit wurden als Weltzeit gelesen. Aus Mitternacht Ortszeit wurde der Vortag — sichtbar in über 1.900 automatisch erzeugten Adressen, die einen Tag zu früh datiert waren.
Die Falle beim Beheben: Naheliegend wäre, im Import einen Tag abzuziehen. Das hätte einen zweiten Fehler erzeugt, weil andere Programmteile das Enddatum bewusst als Zeitpunkt behandeln — ein Fest wäre an seinem letzten Tag als beendet gegolten. Korrigiert wurde deshalb die Anzeige, nicht die Datenhaltung.
Was wir gelernt haben: Bei Datumsfehlern zuerst klären, welche Bedeutung ein Feld im System hat, bevor man rechnet. Die bestehenden Adressen blieben unverändert — sie umzubenennen hätte 1.900 Weiterleitungen erzeugt für einen rein kosmetischen Gewinn.
Die offene Tür im Nebenraum
Beim Bau einer Bearbeitungsfunktion fiel auf, dass die daneben liegende Löschfunktion keinerlei Zugangsprüfung hatte. Ein einzelner Aufruf ohne Anmeldung genügte, um beliebige Datensätze zu entfernen — nachgewiesen mit einem Wegwerf-Eintrag.
Entstanden war das nicht aus Nachlässigkeit, sondern aus Reihenfolge: Der Endpunkt stammte aus einer frühen Phase, in der es noch keine Benutzerkonten gab. Als sie hinzukamen, wurden die neuen Funktionen abgesichert — die alte blieb, wie sie war.
Warum es keine Prüfung fand: Die Funktion war in der Oberfläche nirgends verlinkt. Sie tauchte in keinem Testfall auf, weil sie in keinem Ablauf vorkam.
Was wir geändert haben: Bei jeder Änderung an einer Schnittstelle prüfen wir seither die benachbarten Endpunkte derselben Datei auf fehlende Zugangsprüfungen — unabhängig davon, ob sie zum Auftrag gehören.
Was diese Fälle verbindet
Keiner davon war ein Programmierfehler im engeren Sinn. Es waren Annahmen: dass eine antwortende Startseite eine funktionierende Seite bedeutet. Dass vorhandene Daten eine Seite rechtfertigen. Dass ein Enddatum ein Enddatum ist. Dass eine unverlinkte Funktion niemanden interessiert.
Auffindbar wurden sie durch etwas Unspektakuläres: regelmäßiges Hinsehen mit Zahlen daneben. Drei Nulltage in einer Statistik waren der Anlass, dem ersten Fall nachzugehen. Ohne diese Reihe hätte der Ausfall Wochen dauern können.
Wir schreiben solche Fälle mit, weil sie sich wiederholen — in anderen Projekten, mit anderer Technik, aber derselben Struktur.
Ein Projekt, das ruhig laufen soll?
Wir bauen Webanwendungen mit Django, Nuxt und Qwik — und betreiben sie danach weiter. Beides zusammen, weil man das eine ohne das andere schlecht beurteilen kann.
Gespräch anfragen