Warning codes
A 200 never means “perfect”. It means we produced a result, and here is
everything that was wrong with it. Every degradation produces a machine-readable
warning at page granularity: silence is forbidden.
Each code has a page of its own at https://docs.kaho.ai/warnings/<code>, which is exactly
the doc_url the warning object carries.
The severity ladder is the billing ladder
Section titled “The severity ladder is the billing ladder”| Severity | What it means | Billing |
|---|---|---|
info | Output is correct; we are telling you something useful | Billed |
degraded | Output for the named scope is best effort and may be wrong | Billed |
critical | We produced no useful content for the named scope | Not billed at page scope |
A critical page-scope warning removes its page from the bill. Nothing else
does, at any severity. That invariant is contractual and machine-checkable in
both directions: every page named by a critical page-scope warning appears in
usage.pages_not_billed, and every page in usage.pages_not_billed has one.
Assert it in your own tests; we do.
A critical document-scope warning bills the pages we did deliver. There is
exactly one, result_truncated: killing work we performed and
charging nothing for it is worse for both sides than delivering it.
At most 1,000 warnings travel in one response, with a trailing warnings_truncated
carrying the true count. warning_summary is computed over the untruncated set,
so alerting never has to walk the array.
Conversion
Section titled “Conversion”Emitted by /v1/convert. The three rows worth reading together are page_empty, which is
informational and billed because a genuinely blank page correctly converts to nothing;
page_has_no_text_layer, which is critical and not billed because an image-only page
produced nothing of value; and page_budget_exceeded, which is named for a deterministic
work budget rather than a timeout, because a wall-clock trigger would make your bill a
function of how busy our machines were.
| Code | Severity | Scope | Billed |
|---|---|---|---|
document_untagged | info | document | Yes |
document_partially_tagged | info | document | Yes |
document_permissions_restricted | info | document | Yes |
metadata_unavailable | info | document | Yes |
page_range_clamped | info | document | Yes |
page_count_declared_mismatch | info | document | Yes |
engine_alias_floating | info | document | Yes |
header_footer_detection_skipped | info | document | Yes |
warnings_truncated | info | document | Yes |
security_fix_applied | info | document | Yes |
security_fix_available | degraded | document | Yes |
form_fields_not_extracted | info | document | Yes |
annotations_not_extracted | info | document | Yes |
result_truncated | critical | document | Delivered pages only |
font_tounicode_broken | degraded | page | Yes |
text_layer_unreliable | degraded | page | Yes |
reading_order_low_confidence | degraded | page | Yes |
multi_column_detected | info | page | Yes |
vertical_text_detected | degraded | page | Yes |
rtl_text_detected | degraded | page | Yes |
table_spans_flattened | info | page | Yes |
table_nested_flattened | degraded | page | Yes |
repeated_content_removed | info | page | Yes |
invisible_text_included | info | page | Yes |
invisible_text_dropped | info | page | Yes |
page_rotation_applied | info | page | Yes |
content_outside_cropbox_dropped | info | page | Yes |
link_scheme_blocked | info | page | Yes |
page_empty | info | page | Yes |
table_not_extracted | degraded | page | Yes |
page_has_no_text_layer | critical | page | No |
page_render_failed | critical | page | No |
page_budget_exceeded | critical | page | No |
Table of contents
Section titled “Table of contents”Emitted by /v1/toc.
| Code | Severity | Scope | Billed |
|---|---|---|---|
toc_outline_unusable | info | document | Yes |
toc_inferred | info | document | Yes |
toc_inference_low_confidence | degraded | document | Yes |
toc_entry_unresolved | info | document | Yes |
toc_truncated | info | document | Yes |
toc_title_sanitized | info | document | Yes |