RAG index stuck on building

RAG Index Stuck on Building? The Real Cause and Fix 

You’ve loaded a few gigabytes of PDFs and Markdown into a self-hosted RAG app. The UI says the index is “Building.” An hour later, it still says “Building.” There are no errors and no crash, just a status that never moves.

The instinct is to blame the vector database. Is it out of memory? Is the disk slow? Is something wrong with the network? Often none of that holds up. htop looks calm, iostat looks fine, and direct queries to the vector store return results. Vectors are clearly being written.

When the database looks healthy and the status still won’t change, the problem almost always sits upstream, in the pipeline that feeds the index and in how that pipeline reports it’s finished.

A “Building” status is just a flag

Most RAG apps run ingestion as a chain of stages:

  1. Loader: finds files and extracts their text
  2. Chunker: splits text into pieces of a set size and overlap
  3. Embedding generator: sends chunks to an embedding model and gets vectors back
  4. Indexer: writes vectors and metadata to the vector store

The “Building” label usually comes from a flag in the app’s metadata store. It flips to “Ready” only when the final stage reports success. If any earlier stage stalls, slows down, or fails without saying so, the flag never flips, even while some vectors keep landing in the database.

That’s why the database can look perfectly healthy while the UI stays stuck.

The usual suspect: embedding rate limits

The most common cause is surprisingly mundane. Each embedding call is fast, but there are a great many of them.

A few gigabytes of documents can produce hundreds of thousands of chunks. Embedding providers cap requests per minute and tokens per minute, often with daily limits too, and going over any one of them returns an HTTP 429 error. Free and entry tiers have tight caps. Failed requests usually still count against the limit, so a pipeline that retries aggressively can make things worse.

If the embedding stage runs synchronously inside one long indexing job, the whole job waits on the slowest, most throttled step. The UI has no way to know whether the job is crawling along or truly stuck.

FastGPT’s own troubleshooting docs describe both versions of this. If you can verify the model connection but indexing shows no progress at all, the vector model setting (vectorModels) is usually missing from the configuration. If progress moves but painfully slowly, the culprit is typically API key limits on the connected model service, and the docs single out free-tier OpenAI accounts specifically.

Other ways a pipeline fails silently

Rate limits aren’t the only trap. A few others show up again and again.

The loader finds files but can’t read them. Wrong permissions, scanned PDFs with no text layer, or malformed files can all make a loader skip content quietly. The status shows activity because the job started, but little or nothing reaches the chunker. The giveaway is a vector store far smaller than the document set should produce.

The chunker chokes on odd structures. Huge tables, a single giant line, or deeply nested Markdown can produce empty or oversized chunks. Oversized chunks can then exceed the embedding model’s input limit and fail one by one.

Retries pile up. A naive retry loop with no backoff hammers a rate-limited API, gets more 429 errors, and never catches up.

Writes fail after the embeddings succeed. Missing write permissions, schema mismatches or dimension mismatches between the model and the index can drop vectors at the last step.

Decouple the stages, but keep the status honest

A common fix is to put a queue between stages, usually between chunking and embedding. The chunker finishes and pushes work into the queue. Separate workers pull chunks, call the embedding API at a controlled pace, and write vectors as they go. If the embedding provider has a short outage, chunks simply wait in the queue instead of killing the whole job.

That’s the right architecture. But one tempting shortcut gets it wrong: marking the index “done” once chunking finishes. Do that and users see a ready index while searches quietly miss half the documents. That’s worse than a stuck status, because nobody knows anything is wrong.

A better approach is to report progress for each stage:

  • Chunked: 12,400 of 12,400
  • Embedded: 8,100 of 12,400
  • Indexed: 8,000 of 12,400

Statuses like “Populating” or “Partially indexed” tell the truth. They also make a stall visible within minutes rather than hours. FastGPT moved in this direction in a recent release. Version 4.17.2 writes vectors back to persisted data rows as training completes, so long or interrupted jobs don’t leave missing or orphaned data. It also adds a training progress dashboard broken down by processing mode, with error inspection and retries.

Make rate limits boring

Several patterns turn rate limits from an outage into background noise.

Batch inputs. Many embedding APIs accept several texts in one request. If you’re hitting request-per-minute limits but have token headroom, batching raises throughput without raising the request count.

Pace requests before they fail. A client-side limiter, such as a token bucket or a capped worker pool sized to your actual limits, spaces out calls instead of reacting after the API refuses them.

Retry with exponential backoff and jitter. Respect the Retry-After header when the provider sends one. Roughly:

for attempt in 1..6:

    response = embed(batch)

    if response.ok: return response

    if response.status == 429:

        wait = retry_after or (2 ** attempt) + random_jitter()

        sleep(wait)

    else:

        raise error

Send batch to dead-letter queue

Use a dead-letter queue. Chunks that keep failing go to a side queue for inspection, so one bad document can’t hold the whole index hostage.

Make writes idempotent. Give each chunk a stable ID, so a retried write updates the existing vector instead of creating a duplicate.

Use batch APIs for big backfills. Some providers offer cheaper, slower batch endpoints. They suit large one-time ingestions that don’t need to finish in minutes.

Run a pre-flight check before the big ingest

A small test run catches most of these problems before you commit gigabytes of documents. Use a sample that includes your messiest file types.

Stage

What to check

LoaderFiles are readable. Sample PDFs, Markdown, and scans parse into real text.
ChunkerChunk size and overlap match settings. No empty or oversized chunks.
Embedding generatorAuthentication works. A small batch succeeds. Rate-limit headers are logged. Vector dimensions match the index.
IndexerWrite permissions work. Sample vectors insert and can be queried. Status updates propagate.
Whole systemCPU, memory, disk, and network stay healthy during the test. Logs for every stage are visible at a useful verbosity.

If you’re running FastGPT specifically, the FastGPT self-hosting guide and the project’s documentation are worth a read before scaling up, especially on model configuration, which is where many indexing stalls begin.

Why it matters beyond the progress bar

A half-built index doesn’t just slow things down. It changes the answers. A RAG system retrieves only what made it into the index, and language models tend to answer confidently from whatever context they get. They’ll repeat whatever they’re fed, gaps included. A silently partial index produces answers that look complete and aren’t.

The cost side matters too. Retries burn tokens, and a badly paced pipeline can pay twice for the same chunks. The same discipline that helps teams cut AI cloud costs applies here: measure each stage before you scale it.

FAQs

Q. Why is my RAG index stuck on “Building” when the vector database works?
Usually because an upstream stage, often embedding generation, is throttled, stalled or failing quietly, so the final “complete” signal never fires.

Q. How do I know whether rate limits are the cause?
Check embedding logs for HTTP 429 responses and rate-limit headers. Steady but very slow progress is a classic sign.

Q. Should I mark the index ready once chunking finishes?
No. Track progress for each stage and show a “populating” state until embeddings and writes catch up.

Q. Why does FastGPT verify my model but show no indexing progress?
FastGPT’s docs point to a missing vectorModels configuration as the usual cause.

Related: What Is a RAG Pipeline? Retrieval-Augmented Generation Works

Tags: