Reliability
Configure request timeouts, retries, rate-limit handling, and cancellation for DeepSeek invocations and streams.
Reliability controls how the SDK behaves when requests take too long, encounter temporary failures, hit rate limits, or need to be cancelled. The following examples demonstrate the timeout, invocation, and streaming cancellation behavior tested with the DeepSeek SDK.
Configure the client
DEEPSEEK_SESSION_ID=your_ds_session_id_valueDEEPSEEK_AUTHORIZATION=your_authorization_valueimport 'dotenv/config';import { DeepSeekWeb, DeepSeekTimeoutError, DeepSeekAbortError, DeepSeekRateLimitError,} from '@orcushq/deepseek'; const dsSessionId = process.env.DEEPSEEK_SESSION_ID;const authorization = process.env.DEEPSEEK_AUTHORIZATION; if (!dsSessionId || !authorization) { throw new Error( 'Missing DEEPSEEK_SESSION_ID or DEEPSEEK_AUTHORIZATION', );} const model = new DeepSeekWeb({ model: 'deepseek-v3', dsSessionId, authorization,});The SDK requires both authentication values. dotenv/config loads them from your .env file; it does not verify whether DeepSeek accepts them.
Timeouts
Use timeoutMs to limit how long an invocation waits for the response headers. The default is 60,000 milliseconds (60 seconds), and 0 disables the timeout. A timeout raises DeepSeekTimeoutError.
const response = await model.invoke( 'Reply with exactly: OK', { timeoutMs: 1, retry: false, },);In the test, a 1 ms timeout produced DeepSeekTimeoutError as expected. This is an intentionally short timeout used to test error handling, not a recommended production setting.
Retries
Retries allow an operation to be attempted again after an eligible transient failure. Configure the retry policy with attempts, delayMs, backoffFactor, and maxDelayMs. The attempts value includes the initial request.
const response = await model.invoke( 'Reply with exactly: Reliability test passed.', { timeoutMs: 30_000, retry: { attempts: 2, delayMs: 100, backoffFactor: 2, maxDelayMs: 500, }, },); console.log('Response:', response.content);This configuration was used in the successful invocation test. Because the request succeeded, that result confirms the invocation worked but does not verify that a retry occurred. Retry and backoff behavior requires a separate test that deliberately produces a retryable failure.
attempts: Maximum number of attempts, including the first request.delayMs: Initial delay between attempts.backoffFactor: Multiplier used to increase the delay after failures.maxDelayMs: Maximum delay between attempts.retry: false: Disables retries where that retry option is applied.
Retry configuration scope
In the current implementation, the constructor-level retry policy is forwarded by stream(), but is not forwarded to the turn-level retry logic used by invoke() and batch(). Use a per-call retry option where supported. Internal transport requests also disable transport-level retries, so do not assume one retry setting controls every network request.
Rate limits
An HTTP 429 response is mapped to DeepSeekRateLimitError. When the upstream service provides a retry hint, the error may expose it through retryAfterMs. The live reliability test did not trigger a rate limit, so this behavior still needs a dedicated test to verify it against the current implementation.
Invocation cancellation
Use AbortController when your application needs to stop an invocation. Pass its signal through the per-call signal option. An intentional cancellation raises DeepSeekAbortError.
const controller = new AbortController();const timer = setTimeout(() => controller.abort(), 100); try { const response = await model.invoke( 'Write a detailed explanation of distributed systems.', { signal: controller.signal, retry: false, }, ); console.log(response.content);} catch (error) { if (error instanceof DeepSeekAbortError) { console.log('PASS: Invocation was cancelled.'); } else { throw error; }} finally { clearTimeout(timer);}The test successfully detected invocation cancellation. The 100 ms delay is for testing; cancellation timing depends on when the request and abort signal are processed.
Streaming cancellation
Streaming produces text incrementally. Use an AbortSignal to stop a stream when the application no longer needs the response. Chunks received before cancellation may already have been printed or processed and cannot be taken back.
const controller = new AbortController();const timer = setTimeout(() => controller.abort(), 5_000); try { const stream = await model.stream( 'Write a long essay about distributed systems.', { signal: controller.signal, retry: false, }, ); for await (const chunk of stream) { if (chunk.content) { process.stdout.write(chunk.content); } } console.log('\nStream completed before cancellation.');} catch (error) { if (error instanceof DeepSeekAbortError) { console.log('\nPASS: Stream was cancelled.'); } else { throw error; }} finally { clearTimeout(timer);}The test printed part of the essay and then reported PASS: Stream was cancelled. This confirms that the cancellation error was recognized. The request may finish before the timer fires, so the timeout is not a guarantee that every run will cancel at exactly five seconds.
Streaming timeouts
The request timeout covers waiting for response headers, not the entire period spent reading the stream body. Use AbortSignal to stop a long-running stream. The test above demonstrates this cancellation pattern.
Test results
- Invocation: Passed. The model returned the expected reliability-test response.
- Timeout: Passed. A 1 ms timeout produced
DeepSeekTimeoutError. - Invocation cancellation: Passed. The abort signal produced
DeepSeekAbortError. - Streaming cancellation: Passed. Partial text was printed before the cancellation was recognized.
- Retries and rate limits: Not yet confirmed by these tests; they require dedicated failure-based tests.