{"record":{"id":"a7bcea11425cdb53","repo":"abhigyanpatwari/GitNexus","slug":"embedding-request-cancelled-safeurl-url-batc","errorCode":null,"errorMessage":"Embedding request cancelled (${safeUrl(url)}, batch ${batchIndex})","messagePattern":"Embedding request cancelled \\((.+?), batch (.+?)\\)","errorType":"exception","errorClass":"HttpEmbeddingError","httpStatus":null,"severity":"info","filePath":"gitnexus/src/core/embeddings/http-client.ts","lineNumber":544,"sourceCode":"          parsed = payload.data;\n          return attemptResp;\n        },\n        breakerKey: HTTP_BREAKER_KEY,\n        retry: {\n          maxAttempts,\n          baseDelayMs: HTTP_RETRY_BACKOFF_MS,\n          capDelayMs: retryCapMs,\n          retryAfterCapMs: retryCapMs,\n          sleep: (ms) => abortableSleep(ms, requestOptions.signal),\n        },\n      },\n    );\n  } catch (err) {\n    if (\n      requestOptions.signal?.aborted ||\n      (err instanceof DOMException && err.name === 'AbortError')\n    ) {\n      throw new HttpEmbeddingError(\n        `Embedding request cancelled (${safeUrl(url)}, batch ${batchIndex})`,\n        { cause: err },\n      );\n    }\n    // Retries are exhausted on a bad 2xx body. Surface the message the sentinel\n    // carried, keeping the underlying parse error in `cause` only — the body\n    // text must never reach the `sanitizeReason` fallback and leak to stderr.\n    if (err instanceof RetryableEmbeddingBodyError) {\n      throw new HttpEmbeddingError(err.terminalMessage, { cause: err.cause });\n    }\n    if (err instanceof RetryableEmbeddingTimeoutError) {\n      throw new HttpEmbeddingError(\n        `${err.message} after ${maxAttempts} attempt(s) (${safeUrl(url)}, batch ${batchIndex})`,\n        { cause: err.cause },\n      );\n    }\n    if (err instanceof CircuitOpenError) {\n      throw new HttpEmbeddingError(","sourceCodeStart":526,"sourceCodeEnd":562,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/core/embeddings/http-client.ts#L526-L562","documentation":"httpEmbedBatch's catch maps AbortError (the caller's AbortSignal aborted, or a DOMException named AbortError) to HttpEmbeddingError 'Embedding request cancelled'. Cancellation is honored across the whole retry loop — abortableSleep and the fetch signal stop retries immediately; this is a cooperative cancel, not a failure.","triggerScenarios":"The caller passes an AbortSignal and aborts it mid-flight: MCP request cancellation, CLI Ctrl+C racing a slow endpoint, or an outer AbortSignal.timeout(...) firing as a timeout while a batch is in progress.","commonSituations":"Editor LSP/MCP clients cancelling in-flight semantic queries, servers with aggressive request deadlines, or tests that abort to clean up.","solutions":["Treat as expected control flow — catch HttpEmbeddingError and inspect cause/name for AbortError instead of retrying.","If it fires spuriously, raise the outer deadline/timeout that owns the signal.","Don't reuse an already-aborted signal across embedding calls.","For real per-request timeouts prefer GITNEXUS_EMBEDDING_HTTP_TIMEOUT_MS so the error is classified as a timeout, not a cancel."],"exampleFix":"// before\nconst ctrl = new AbortController();\nsetTimeout(() => ctrl.abort(), 100); // too tight\nawait httpEmbedQuery(q, { signal: ctrl.signal });\n// after\nconst ctrl = new AbortController();\nsetTimeout(() => ctrl.abort(), 60_000);\ntry {\n  await httpEmbedQuery(q, { signal: ctrl.signal });\n} catch (e) {\n  if (e instanceof HttpEmbeddingError && e.cause?.name === 'AbortError') return []; // graceful cancel\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"const aborted = (signal?: AbortSignal): boolean => !!signal?.aborted;\nif (aborted(mySignal)) return; // don't even start","typeGuard":"const isEmbeddingCancel = (e: unknown): boolean =>\n  e instanceof Error && e.message.includes('Embedding request cancelled');","tryCatchPattern":"try {\n  vectors = await httpEmbed(texts, { signal });\n} catch (e) {\n  if (isEmbeddingCancel(e) || (e as DOMException)?.name === 'AbortError') {\n    return; // cooperative cancel — not an error path\n  }\n  throw e;\n}","preventionTips":["Check signal.aborted before starting a batch; never pass an already-aborted signal.","Use a dedicated AbortSignal.timeout only when you want timeout semantics; combine caller+timeout signals with AbortSignal.any.","Size deadlines to batch size so user cancellation doesn't masquerade as failures."],"tags":["embeddings","http","abort","cancellation","signals"],"backgroundTag":"request-aborted","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}