Skip to main content
This is Part 3 of the Build an End-to-End RAG Pipeline series: the ingestion side of RAG. Parts 1 and 2 followed the happy path, but production code can’t assume it: requests fail, services blip, and you need to confirm that an operation actually took effect. This part builds a small resilient client and uses it to interpret API errors, retry transient failures, and verify ingestion health. The retrieval side (semantic search and grounded answers) is covered in the Building Custom Search tutorial and the Grounded Completions guide.
Gloo AI does not include a monitoring or health-check endpoint. Resilience is built from the same item APIs you’ve already used, plus disciplined error handling on the client side.

Pipeline at a Glance

1

Publisher setup (Studio)

Create the publisher that owns your content: Part 1.
2

Ingest content with metadata

Upload files and enrich them: Part 1.
3

Verify indexing

Poll item status until your content is searchable: Part 1.
4

Semantic search

Query your content. Deep dive: Building Custom Search.
5

Grounded completions with sources

Answer questions from your content with citations. Deep dive: Grounded Completions, which sets rag_publisher to your publisher name.
6

Content lifecycle

Update, bulk-edit, and delete content: Part 2.
7

Verification, errors & resilience

Error handling and retry patterns: covered below.

Prerequisites

Before starting, you need:

Step 1: Parse Errors and Retry

A resilient client does two things on every request: it turns failures into a normalized error (status, code, message) that carries the body’s error.retryable flag, and it retries only the failures the API marks as transient. The authoritative signal is that retryable boolean (Errors): retry when it is true, and hand the error straight back to the caller when it is false. A 500 with retryable: false (for example 3001 INTERNAL_ERROR) will not succeed on a second attempt. The transient status set (500, 502, 503, 504) is only a fallback for responses whose error body is missing or unparseable, where there is no flag to read. For the general rules this step applies, including retry budgets and Retry-After, see Error Handling and Retries. The parser normalizes all of the Data Engine’s error shapes: {"detail": {"code", "message"}}, {"detail": "..."}, and {"error", "message"}.
These snippets are simplified for readability. The cookbook client also retries network-level failures, and applies the same retry policy to multipart uploads. Both implement the same patterns.

Step 2: Interpret API Error Responses

With request and parse_error in place, catch the normalized error and read its status, code, and message. The calls below deliberately trigger three common failures: a missing item (404), a malformed ID (400), and a rejected token (403).

What You’ll See

A rejected or malformed API key returns 403, not 401. A 403 can also be a legitimate permission denial (for example, an item that belongs to another publisher), so the client does not retry it. API keys are sent as-is on every request, so there is no token to refresh; if you get a 401 or 403, check that the key is correct and has not been revoked.On a legacy client-credentials integration, a genuinely expired access token typically returns 401, and the fix is to fetch a new token once and retry (not on 403). Migrating to an API key removes that step; see Legacy: client credentials and OAuth.

Step 3: Retry Transient Failures

The retry loop from Step 1 retries transient failures (a 503, a dropped connection) instead of surfacing them. Here it is in isolation, recovering from a service that fails twice before succeeding.
A healthy API won’t return a 5xx on demand, so this example simulates one to exercise the backoff path. In production the same path handles real 5xx responses and network errors.

What You’ll See

Step 4: Verify Ingestion Health

With no health endpoint, you verify by checking the items you care about. Upload a batch, wait for indexing, then fetch each item’s status and roll it up into a summary, treating a 404 as “not found” rather than an error so one missing item doesn’t abort the check. The example deliberately includes a random ID to show that path.

What You’ll See

The two uploaded items report COMPLETED; the random ID is counted as not found instead of throwing.

Run the Complete Example

The cookbook ties it together (a resilient client that handles errors, retries, and a full upload → verify → clean-up health check) in all six languages. From the cookbook repository, install dependencies, copy .env.example to .env and add your credentials, then run it:
You’ll see:

Working Code Sample

View Complete Code

Clone or browse the complete resilient client for all 6 languages (JavaScript, TypeScript, Python, PHP, Go, Java) with setup instructions and the sample content files.

Troubleshooting

A request fails immediately instead of retrying

Retry only when the error’s retryable flag is true; when it is false, fail fast regardless of status (a 500 such as 3001 INTERNAL_ERROR is not retried). Client errors (400, 401, 403, 404, 422) are not retryable and fail fast. The status fallback (500/502/503/504) applies only to responses whose error body is missing or unparseable.

Retries never stop / take too long

Check your backoff cap. With base-2 exponential backoff and MAX_RETRIES = 4, the waits are 1s, 2s, 4s, 8s. Lower MAX_RETRIES or cap the delay for latency-sensitive paths.

Empty error message

Some error responses carry a code but no message. The parser falls back to the HTTP reason phrase (for example, Forbidden) so you always have something to log.

403 on a token you believe is valid

A malformed or rejected token returns 403. Re-check your API key and confirm it has not been revoked. See the Authentication Tutorial.

Next Steps

That completes the Build an End-to-End RAG Pipeline series. You’ve set up a publisher and ingested content (Part 1), managed its lifecycle (Part 2), and made the integration resilient (Part 3). From here:
  1. Building Custom Search: surface your content to users with the Search API
  2. Grounded Completions: answer questions from your content with citations (set rag_publisher to your publisher name, the value the grounded guides document, rather than the Publisher ID used for ingestion)
  3. Fold the resilient client into your own service for consistent error handling and retries on every Gloo AI call.
To learn how to judge the answers your pipeline produces, read When RAG Works and When It Doesn’t in the Learning Center.