{"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":495,"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 CircuitOpenError) {\n      throw new HttpEmbeddingError(\n        `Embedding endpoint circuit open (${safeUrl(url)}, batch ${batchIndex}): retry in ${Math.ceil(err.retryAfterMs / 1000)}s`,\n        { cause: err },\n      );\n    }\n    if (err instanceof DOMException && err.name === 'TimeoutError') {\n      throw new HttpEmbeddingError(","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus/src/core/embeddings/http-client.ts#L477-L513","documentation":"An HttpEmbeddingError thrown from httpEmbedBatch's catch block when the caller's AbortSignal is aborted (or the error is a DOMException AbortError). It is a clean, terminal wrapping of a user-initiated cancellation — not a failure. The message includes the safe URL and batch index for context, and the original abort error is preserved in `cause`.","triggerScenarios":"httpEmbedBatch (via httpEmbed or httpEmbedQuery) is called with requestOptions.signal, and that signal is aborted — either by the caller directly (controller.abort()), by a higher-level operation cancelling an analyze run, or by process shutdown. Also fires if the internal abortableSleep between retries is interrupted by abort.","commonSituations":"User cancels a long indexing run (Ctrl-C routed to abort). MCP server shuts down mid-query. A watchdog aborts a stalled embed. Test teardown aborts an in-flight request.","solutions":["Treat this as expected, not an error: if you aborted on purpose, no fix is needed — log it at info/debug level and exit cleanly.","If it fires unexpectedly, find the caller that calls controller.abort() on the signal you passed in (EmbeddingRequestOptions.signal).","Pass a fresh, unshared AbortSignal per embed call if a shared signal is being aborted by an unrelated operation.","Increase GITNEXUS_EMBEDDING_HTTP_TIMEOUT_MS if the abort is actually a timeout misattributed as cancellation (though true timeouts surface as error 129)."],"exampleFix":"// before: a shared controller is aborted elsewhere\nconst shared = new AbortController();\n// ... other code calls shared.abort() ...\nawait httpEmbed(texts, { signal: shared.signal });\n\n// after: dedicated signal per embed call\nconst embedCtl = new AbortController();\nawait httpEmbed(texts, { signal: embedCtl.signal });","handlingStrategy":"try-catch","validationCode":"// Pass a dedicated, unshared signal and only abort it intentionally.\nconst ctl = new AbortController();\n// ... if you really must cancel: ctl.abort();\nawait httpEmbed(texts, { signal: ctl.signal });","typeGuard":"import { isHttpEmbeddingError } from 'gitnexus';\nconst isCancelled = (e: unknown): boolean =>\n  isHttpEmbeddingError(e) && e instanceof Error && e.message.startsWith('Embedding request cancelled');","tryCatchPattern":"try {\n  await httpEmbed(texts, { signal: ctl.signal });\n} catch (e) {\n  if (isHttpEmbeddingError(e) && e.message.includes('request cancelled')) {\n    // user-initiated cancel; exit cleanly, do not treat as a failure\n    return;\n  }\n  throw e;\n}","preventionTips":["Pass a fresh AbortController per embed call rather than reusing a shared one.","Log cancellations at info/debug, not error, level.","Do not share an abort signal across unrelated operations."],"tags":["abort","cancellation","embeddings","control-flow"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}