Skip to content

dd_error_report_api

See also: JSON API v1 · dispatch

The master installation's error-report intake: remote installations' servers relay admin-submitted error reports here machine-to-machine. It is a TS-native surface with no twin in the previous engine (WC-017), and its one pre-auth action is receive_report.

The registry entry is src/core/api/dispatch.tserrorReportApiActions (src/core/api/handlers/dd_error_report_api.ts). Reachability is gated before the handler by the dispatcher's Gate 1c: the request is refused unless the receiver is explicitly enabled (DEDALO_ERROR_REPORT_RECEIVER) and the caller IP is on the allowlist. There is no session and no CSRF token — it is machine-to-machine intake, not a browser action.

How to call

  • POST JSON with dd_api: "dd_error_report_api" and action: "receive_report". The report payload rides in options.

Common fields

  • options carries the self-reported report body against a strict shared schema (src/core/error_report/schema.ts) — entity, dedalo_version, user_id, section_tipo, section_id, page_url, description, js_errors, and context fields (langs, user_agent, screenshot, …). Unknown fields are rejected.

The intake discipline runs in a fixed order

The handler owns, in order: (1) a per-trusted-hop-IP sliding-window throttle — every request spends budget, so junk floods and token-guessing loops rate-limit alike; (2) an optional constant-time shared-token check — a wrong/missing token answers the exact unregistered-action shape, no existence leak; (3) a total-size clamp (the 256 MiB global body cap is useless here); (4) the strict shared schema (unknown fields rejected); (5) append to the store, stamping source_ip from the trusted hop. It never fetches or resolves any URL-shaped field (no SSRF), never logs report text (log-injection), and never echoes internals in error envelopes.

receive_report

  • Purpose: Accept and store one error report relayed from a remote installation.
  • Accepts: the report body in options, matching the strict wire schema; the shared token (when configured) travels out-of-band, checked constant-time.
  • Returns: envelope v2. A stored report is { ok: true, request_id, data: true, report_id: <int> }report_id is the top-level extension key the relaying installation reads beside ok. Any refusal is { ok: false, request_id, error: { code, category, message, label_key, retryable } }; the message is always a terse registry sentence, never the payload or field-level detail.

Example Request: receive_report

{
  "dd_api": "dd_error_report_api",
  "action": "receive_report",
  "options": {
    "entity": "Example Archive",
    "dedalo_version": "7.0.0",
    "user_id": 42,
    "section_tipo": "oh1",
    "section_id": 3,
    "page_url": "https://example.org/…",
    "description": "Save button did nothing",
    "js_errors": []
  }
}

Example Response: receive_report

{
  "ok": true,
  "request_id": "c0ffee70",
  "data": true,
  "report_id": 128
}

Notes

  • Refusals are deliberately indistinguishable: a disabled receiver, a wrong token, and an unregistered action all answer the same body — request.unknown_action (HTTP 400, "Undefined or unauthorized method (action)"), down to the echoed details.action. An oversize or schema-invalid body answers request.invalid (HTTP 400, "Invalid error report"); a throttled caller gets rate.limited (HTTP 429); a store failure answers internal.unexpected (HTTP 500) and never echoes the report.
code status when
request.unknown_action 400 receiver disabled, caller IP not allowed, wrong/missing shared token, or the action is not receive_report.
request.invalid 400 body over the endpoint size clamp, or it failed the strict schema (unknown fields included).
rate.limited 429 the trusted-hop IP spent its sliding-window budget.
internal.unexpected 500 the intake store could not append.
- Only source_ip (the trusted-hop address) and received_at are master-trusted; every other field is stored as self-reported context.