Zum Hauptinhalt springen

Ein fehlgeschlagenes Rendering nachstellen

Ein Rendering ist in Produktion fehlgeschlagen, und der Fehler zeigt auf Zeile 41 der Vorlage. Um ihn zu beheben, brauchen Sie, was ihn ausgelöst hat: die Daten dieser Anfrage. Bewahrt der Workspace Render-Anfragen auf, holt ein einziger Befehl diese Daten als Datensatz in Ihr Projekt, rendert sie lokal und zeigt den Fehler mit Zeile und Spalte.

formfeed renders pull rnd_7da09ab6cd9946b798c187c2a9350852 --run

1. Render-Anfragen aufbewahren​

Formfeed bewahrt die Daten einer Anfrage nur auf, wenn der Workspace das verlangt. Ein Inhaber oder Admin schaltet das unter Einstellungen im Abschnitt des Workspace (Workspace „…“) mit Render-Anfragen aufbewahren ein. Jeder Workspace hat seine eigene Einstellung.

EinstellungPläneWas aufbewahrt wird
Aus (Standard)AlleNichts. Ein asynchrones Rendering hält seine Anfrage nur, solange es in der Warteschlange wartet; sie wird gelöscht, sobald das Rendering fertig ist
24 StundenAb StarterDie Anfrage jedes Renderings, synchron und asynchron, 24 Stunden nach dem Ende des Renderings
7 TageAb ProDasselbe, 7 Tage lang
  • Die Einstellung gilt ab dem Moment, in dem sie eingeschaltet wird. Renderings, die vorher fertig wurden, lassen sich nicht holen.
  • Der Plan begrenzt die Wahl: Nach einem Downgrade werden Anfragen sofort nur noch so lange aufbewahrt, wie der neue Plan erlaubt (ein Workspace mit 7 Tagen bewahrt im Starter-Plan 24 Stunden auf und im Free-Plan nichts).
  • Passwörter der Nachbearbeitung werden nie aufbewahrt. Ein passwortgeschütztes Rendering lässt sich deshalb nicht aus dem Render-Protokoll erneut rendern, weil die Kopie ungeschützt herauskäme.
  • Renderings mit Test- und Live-Schlüsseln werden gleich behandelt.
  • Eine Anfrage wird gelöscht, wenn ihr Zeitraum endet (die Bereinigung läuft stündlich), und in jedem Fall 7 Tage nach ihrem Eingang.

Eine aufbewahrte Anfrage kann personenbezogene Daten enthalten: Namen, Adressen, IBANs. Schalten Sie die Einstellung ein, wenn Sie sie brauchen, wählen Sie bevorzugt 24 Stunden und lesen Sie unten Personenbezogene Daten.

2. Das Rendering finden​

Die ID des Renderings (rnd_…) steht im Render-Protokoll der App, im Webhook render.failed, in der Antwort auf die Anfrage und in der CLI:

formfeed renders list --status failed --since 2026-09-13T00:00:00Z

3. Ins Projekt holen​

Führen Sie das in einem Projekt aus, das Sie mit formfeed init und formfeed templates pull angelegt haben:

formfeed renders pull rnd_7da09ab6cd9946b798c187c2a9350852

Die CLI liest die aufbewahrte Anfrage und schreibt die Daten nach templates/<slug>/data/render-<letzte 6 Zeichen der ID>.json, neben die anderen Datensätze der Vorlage. Die Vorlage braucht einen Ordner im Projekt (vorher formfeed templates pull <slug>), und nur Renderings einer Vorlage lassen sich holen, keine Renderings aus rohem HTML oder einer URL.

  • --as <name> wählt den Dateinamen: --as missing-vat-id schreibt data/missing-vat-id.json. Buchstaben, Ziffern, _, . und -; default ist reserviert.
  • Eine vorhandene Datei wird nur mit --force überschrieben.
  • Hat das Rendering eine andere Vorlagenversion verwendet als die in Ihrem Ordner, nennt die CLI beide Versionsnummern. Die Daten passen dann womöglich nicht zu Ihrer lokalen Vorlage; formfeed templates pull bringt den Ordner auf den aktuellen Stand.

Das Holen braucht den Scope render:input. formfeed login gibt ihn Editoren, Admins und Inhabern; ein API-Schlüssel hat ihn nur, wenn Sie ihn beim Anlegen des Schlüssels auswählen.

Lässt sich die Anfrage nicht holen, bricht der Befehl mit einer Meldung und Exit-Code 2 ab (die Anfrage ist nicht aufbewahrt, oder das Rendering gehört nicht zu diesem Workspace) oder mit 3 (dem Schlüssel fehlt render:input); siehe Exit-Codes.

4. Lokal rendern​

formfeed renders pull rnd_7da09ab6cd9946b798c187c2a9350852 --run

--run rendert den neuen Datensatz sofort mit der lokalen Engine, wie formfeed test es tut, mit der Locale der ursprünglichen Anfrage, und gibt die Diagnose mit Vorlagendatei, Zeile und Spalte aus. Rendert die Vorlage nicht, endet der Befehl mit Exit-Code 1 und eignet sich so auch für Skripte. Bei einem fehlgeschlagenen Rendering ist das die Reproduktion in einem Befehl. Danach funktioniert der Datensatz wie jeder andere:

formfeed dev invoice # Live-Vorschau, während Sie die Vorlage korrigieren
formfeed validate # jede Vorlage gegen ihre Datensätze kompilieren

Korrigieren Sie die Vorlage, pushen Sie eine neue Version und behalten Sie den Datensatz: Von nun an fängt formfeed validate in der CI denselben Fehler ab, bevor er in Produktion gelangt.

5. Ein gutes Rendering zum Test machen​

Ein Rendering, das richtig herausgekommen ist, ist ein Regressionstest in spe:

formfeed renders pull rnd_f3c70d646f1ee82bde1e266ee2689a9b --as order-with-40-lines --snapshot

--snapshot rendert die Daten lokal und schreibt das Ergebnis nach templates/<slug>/tests/__snapshots__/order-with-40-lines.html (.xml bei einer Word- oder PowerPoint-Vorlage). formfeed test schlägt dann fehl, sobald eine Änderung an der Vorlage dieses Dokument verändert. Bei einem fehlgeschlagenen Rendering, an dem nichts freizugeben ist, lehnt die CLI --snapshot ab (Exit-Code 2); holen Sie es stattdessen mit --run.

Personenbezogene Daten​

Ein geholter Datensatz ist eine Kopie der Anfrage eines Kunden auf Ihrer Festplatte. Schwärzen Sie ihn, bevor Sie ihn committen:

formfeed renders pull rnd_7da09ab6cd9946b798c187c2a9350852 --redact

--redact ersetzt Werte, behält aber die Form der Daten, damit die Vorlage dieselben Zweige nimmt:

WertWird zu
StringsPlatzhalter gleicher Länge, die die Zeichenklassen behalten (Großbuchstaben werden zu A, andere Buchstaben zu a, Ziffern zu 0, alles andere bleibt): jane@mail.test wird zu aaaa@aaaa.aaaa, DE36 0000 0000 0000 0000 00 zu AA00 0000 0000 0000 0000 00
ZahlenBleiben, weil es beim Fehler meist um sie geht
Wahrheitswerte und nullBleiben

Mit Pfaden werden nur diese Felder geschwärzt: --redact customer.* items[].name iban. Ein Pfad geht mit Punkten von der Wurzel der Daten aus; * steht für einen beliebigen Schlüssel oder Array-Eintrag, [] für jeden Eintrag eines Arrays, und ein Pfad, der auf einem Objekt oder Array endet, schwärzt alles darunter. Setzen Sie Pfade mit * in Anführungszeichen, wenn Ihre Shell sie sonst expandiert. Als Standard für alle im Projekt legen Sie das in formfeed.json fest:

{
"pull": { "redact": ["customer.*", "iban"] }
}

Mit dieser Einstellung schwärzt jedes formfeed renders pull diese Pfade, auch --redact ohne Pfade; --no-redact lässt das für einen Aufruf aus. Ganz ohne Schwärzung erinnert die CLI daran, dass die Datei personenbezogene Daten enthalten kann. Weitere Hinweise:

  • Halten Sie die Aufbewahrung so kurz, wie Ihre Fehlersuche es verlangt. Schalten Sie sie wieder aus, sobald das Problem gelöst ist.
  • Geben Sie render:input nur Personen und Schlüsseln, die Vorlagen debuggen. Eine Produktionsintegration braucht ihn nie.
  • Jeder Lesezugriff auf eine aufbewahrte Anfrage, aus der CLI, der API oder der App, wird als render.input_read ins Audit-Log der Organisation geschrieben. Die Seite Aktivität zeigt das Audit-Log im Pro-Plan (letzte 30 Tage), im Business-Plan (365 Tage) und bei Enterprise.
  • Löschen Sie geholte Dateien, die Sie nicht mehr brauchen, und teilen Sie ungeschwärzte nicht in Tickets oder Chats.

In der App​

Öffnen Sie Renderings und klicken Sie ein Rendering an, um sein Detailblatt zu öffnen. Dessen Abschnitt Anfrage bietet Editoren, Admins und Inhabern drei Aktionen, solange die Anfrage aufbewahrt wird (wird sie es nicht, sagt der Abschnitt das und verlinkt die Einstellungen):

  • Mit diesen Daten im Editor öffnen (nur bei Renderings einer Vorlage) öffnet die Vorlage im Editor mit den Daten der Anfrage als neuem, ungespeichertem Datensatz, benannt wie in der CLI, und wählt die Version aus, die das Rendering verwendet hat, wenn es nicht die neueste ist. Gespeichert wird erst, wenn Sie speichern; dann wird der Datensatz wie jede Änderung an Datensätzen Teil einer neuen Version.
  • Als curl kopieren kopiert die Anfrage an POST /v1/renders mit den Daten inline und $FORMFEED_API_KEY als Platzhalter, nie mit einem echten Schlüssel.
  • Anfrage herunterladen (JSON) speichert die aufbewahrte Anfrage, in der Form der Antwort der API.

Erneut rendern am Fuß des Blatts (Editoren, Admins und Inhaber) reiht dieselbe Anfrage noch einmal im Workspace ein: dieselbe Vorlagenversion, dieselben Daten, Optionen und dieselbe Umgebung, als asynchrones Rendering. Es erscheint als neues Rendering im Render-Protokoll, dessen meta unter replay_of die ID des ursprünglichen trägt, und kostet Einheiten wie jedes Rendering. Es braucht die aufbewahrte Anfrage und wird bei einem passwortgeschützten Rendering und bei einem Aufruf eines PDF-Tools abgelehnt, den Sie über die API wiederholen.

Das fehlgeschlagene Dokument. Schlägt ein Rendering fehl, nachdem sein HTML zusammengesetzt war (ein Rendering einer Vorlage oder aus html, kein url-Rendering), bewahrt Formfeed dieses zusammengesetzte HTML 24 Stunden lang als Ausgabe failed-render.html auf, unter Ausgaben im Blatt, für jedes Mitglied, ob Anfragen aufbewahrt werden oder nicht. Es enthält die Daten der Anfrage; deshalb ist es privat und wird nach einem Tag gelöscht. Öffnen Sie es im Browser, um zu sehen, was Chromium bekommen hat.

Über die API​

GET /renders/{id}/input liefert die aufbewahrte Anfrage, mit einem Schlüssel, der render:input hat:

curl https://api-eu.formfeed.dev/v1/renders/rnd_7da09ab6cd9946b798c187c2a9350852/input \
-H "Authorization: Bearer $FORMFEED_API_KEY"
{
"render_id": "rnd_7da09ab6cd9946b798c187c2a9350852",
"template": { "id": "tpl_7c1e…", "slug": "invoice", "version": 12, "channel": "published" },
"data": { "invoice": { "number": "2026-0042", "lines": [ … ] } },
"locale": "de-DE",
"output": "pdf",
"meta": { "order_id": "8812" },
"environment": "live",
"created_at": "2026-09-13T08:14:02Z"
}

Das ist, was das Dokument erneut rendert, kein interner Datensatz: Vorlage und Version, die Daten, die Locale, das Ausgabeformat und die Optionen (settings, filename, post ohne Passwörter). Ein Rendering aus rohem HTML trägt html und engine statt template, ein URL-Rendering url. Felder, die nicht zutreffen, fehlen.

Bewahrt der Workspace keine Anfragen auf oder ist die Frist abgelaufen, lautet die Antwort 410 render_input_expired mit dem aktuellen request_data_retention des Workspace (off, 24h oder 7d) im Problem:

{
"type": "https://docs.formfeed.dev/errors/render-input-expired",
"status": 410,
"code": "render_input_expired",
"detail": "The request of this render was not kept: the workspace does not keep render requests (Settings, Keep render requests)",
"request_data_retention": "off"
}

Eine Rendering-ID, die nicht zum Workspace des Schlüssels gehört, antwortet mit 404 not_found, ein Schlüssel ohne render:input mit 403 forbidden. Jeder erfolgreiche Lesezugriff wird wie der aus der CLI protokolliert. Die SDKs bieten client.renders.input(id) in TypeScript und Python.