Skip to content

fix: stabilize code indexing retries#10465

Open
marius-kilocode wants to merge 2 commits into
mainfrom
fix-indexing-retry-robustness
Open

fix: stabilize code indexing retries#10465
marius-kilocode wants to merge 2 commits into
mainfrom
fix-indexing-retry-robustness

Conversation

@marius-kilocode
Copy link
Copy Markdown
Collaborator

@marius-kilocode marius-kilocode commented May 20, 2026

Large code indexing runs can overload embedding providers with bursty requests, then leave incremental updates looking complete even when replacement work failed.
This change bounds indexing embedding pressure, preserves existing vectors until replacements are ready, and keeps failed incremental work retryable and visible instead of reporting a false complete state.
Settings saves also finish their UI acknowledgement when the post-write config refresh stalls during reload churn, so persisted config changes do not leave the settings surface stuck dirty.
Fixes #8311.

@marius-kilocode marius-kilocode enabled auto-merge May 20, 2026 21:23
try {
await this.vectorStore.deletePointsByMultipleFilePaths(unique)
return undefined
} catch (error: any) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: catch (error: any) with return error as Error is unsafe and violates the style guide's "avoid any" rule.

If error is a non-Error value (e.g. a plain string or number), casting it as Error is a type lie — callers that call .message on the returned value will get undefined. Consider:

const err = error instanceof Error ? error : new Error(String(error))
return err

This pattern is pre-existing in the file but is newly introduced in _clearBatchReplacements.

export const INITIAL_RETRY_DELAY_MS = 500
export const PARSING_CONCURRENCY = 10
export const MAX_PENDING_BATCHES = 20 // Maximum number of batches to accumulate before waiting
export const EMBEDDING_REQUEST_CONCURRENCY = 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: EMBEDDING_REQUEST_CONCURRENCY = 1 is a hard-coded global constant shared by both DirectoryScanner and FileWatcher. Setting it to 1 fully serializes all embedding calls, which is correct for rate-limit pressure but significantly reduces throughput on large workspaces where the provider isn't rate-limiting.

Consider making this user-configurable (e.g. as a config key) or at least a higher default (e.g. 3) that can be overridden, rather than a fixed compile-time value.

if (this._cancelled) return undefined

log.debug(`Creating embeddings for ${batchTexts.length} texts`)
const { embeddings } = await this.embedLimit(() => this.embedder.createEmbeddings(batchTexts))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: The embedding step is now extracted outside the retry loop, which is correct — there's no point regenerating identical embeddings on retry. However, note that the deletion step (lines 594–631) still runs on every retry attempt. If the first attempt successfully deletes but then the upsert fails, the second retry will call deletePointsByMultipleFilePaths again on already-deleted paths. This is a pre-existing behavior and likely idempotent in Qdrant, but it may be worth a comment near the deletion step noting this is intentionally idempotent.

@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented May 20, 2026

Code Review Summary

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-indexing/src/indexing/processors/file-watcher.ts 308 catch (error: any) with return error as Error is unsafe — non-Error throws are cast without wrapping

SUGGESTION

File Line Issue
packages/kilo-indexing/src/indexing/constants/index.ts 44 EMBEDDING_REQUEST_CONCURRENCY = 1 is a hard-coded global constant that can't be tuned without a code change
packages/kilo-indexing/src/indexing/processors/scanner.ts 536 Deletion step inside retry loop re-deletes already-deleted paths on retry — worth a comment noting idempotence assumption
Other Observations (not in diff)
  • deadline() dangling promise: When deadline times out in handleUpdateConfig, the inner IIFE (retry() + global.config.get()) continues running in the background. This is acceptable — JS has no built-in cancellation without AbortController, and stalled HTTP requests will eventually resolve or error without holding meaningful resources.
  • Mutex early-return is safe: The return inside try at openai-compatible.ts:466 and openrouter.ts:385 is inside a try/finally block — the finally still calls release(), so the mutex is not leaked.
  • _clearBatchReplacements success + upsert failure: If _clearBatchReplacements succeeds but _executeBatchUpsertOperations then fails all retries, the old vectors are permanently gone and new ones not stored. Pre-existing limitation; this PR does not worsen it.
Files Reviewed (13 files)
  • .changeset/quiet-indexes-retry.md — no issues
  • packages/kilo-indexing/src/indexing/constants/index.ts — 1 suggestion
  • packages/kilo-indexing/src/indexing/embedders/openai-compatible.ts — no issues
  • packages/kilo-indexing/src/indexing/embedders/openrouter.ts — no issues
  • packages/kilo-indexing/src/indexing/orchestrator.ts — no issues
  • packages/kilo-indexing/src/indexing/processors/file-watcher.ts — 1 warning, 1 suggestion
  • packages/kilo-indexing/src/indexing/processors/scanner.ts — 1 suggestion
  • packages/kilo-indexing/test/kilocode/indexing/embedders/openai-compatible.test.ts — no issues
  • packages/kilo-indexing/test/kilocode/indexing/orchestrator.test.ts — no issues
  • packages/kilo-indexing/test/kilocode/indexing/processors/file-watcher.test.ts — no issues
  • packages/kilo-indexing/test/kilocode/indexing/processors/scanner.test.ts — no issues
  • packages/kilo-vscode/src/services/cli-backend/retry.ts — no issues (new deadline() utility is correctly implemented)
  • packages/kilo-vscode/src/KiloProvider.ts — no issues (deadline integration and optimistic fallback look correct)
  • packages/kilo-vscode/tests/unit/kilo-provider-indexing-refresh.test.ts — no issues

Fix these issues in Kilo Cloud


Reviewed by claude-sonnet-4.6 · 341,142 tokens

Review guidance: REVIEW.md from base branch main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Uncontrolled parallel embedding requests when indexing codebase wich leads to exponential retries and 429 storm

1 participant