| name | error-handling |
| summary | Couchbase SDK error handling โ UnambiguousTimeoutException vs AmbiguousTimeoutException, DocumentNotFoundException, CasMismatchException, DurabilityImpossibleException, SDK debug logging, sdk-doctor connectivity diagnostics, retryable vs non-retryable errors, circuit breaker, error best practices |
| description | Couchbase SDK error handling โ UnambiguousTimeoutException vs AmbiguousTimeoutException, DocumentNotFoundException, CasMismatchException, DurabilityImpossibleException, SDK debug logging, sdk-doctor connectivity diagnostics, retryable vs non-retryable errors, circuit breaker, error best practices |
| metadata | {"last_verified":"2026-05","handoff":[{"condition":"user asks about CAS, bulk ops, sub-document, or SDK patterns","type":"variant","skill":"sdk-patterns-python"},{"condition":"user asks about transactions or atomic multi-document operations","type":"variant","skill":"transactions-python"},{"condition":"user asks about cluster health or metrics","skill":"monitoring"},{"condition":"user asks about Couchbase fundamentals or core concepts","skill":"getting-started"}]} |
Language routing: The SDK patterns and transactions handoffs in the frontmatter are
variant edges โ they default to Python but apply to all languages. If the user's language
is known, route to the matching sdk-patterns-<lang> or transactions-<lang> skill
directly. If unknown, ask before routing.
Error Handling
The two timeout types
This is the most confusing error distinction in the SDK.
| Exception | Meaning | Safe to retry? |
|---|
UnambiguousTimeoutException | Operation timed out before being sent to the server. The mutation did not happen. | โ
Yes |
AmbiguousTimeoutException | Operation timed out after being sent. The mutation may or may not have happened. | โ ๏ธ Only if idempotent (upsert/replace with CAS) |
The exception class names are consistent across all SDKs:
- Java / .NET / Scala / PHP:
UnambiguousTimeoutException, AmbiguousTimeoutException
- Python:
UnambiguousTimeoutException, AmbiguousTimeoutException
- Go:
gocb.ErrUnambiguousTimeout, gocb.ErrAmbiguousTimeout
- Node.js:
couchbase.UnambiguousTimeoutError, couchbase.AmbiguousTimeoutError
- Rust:
ErrorKind::ServerTimeout for server-side timeout, plus ErrorKind::DocumentNotFound, ErrorKind::DocumentExists, and ErrorKind::CasMismatch for common KV outcomes
For language-specific catch/match syntax, load the matching sdk-patterns-<lang> skill.
Common errors and what they mean
| Error | Cause | Action |
|---|
DocumentNotFoundException | Key does not exist | Expected โ handle gracefully |
DocumentExistsException | insert() on existing key | Use upsert() or handle conflict |
CasMismatchException | Concurrent modification | Retry the read-modify-write loop |
AmbiguousTimeoutException | Sent to server, no response in time | Retry if idempotent |
UnambiguousTimeoutException | Never sent to server | Retry safely |
DurabilityImpossibleException | Not enough replicas for requested durability | Reduce durability level or add nodes |
DurabilityAmbiguousException | Durability state unknown after timeout | Check document state before retrying |
TemporaryFailureException | Server temporarily overloaded | Retry with backoff |
ValueTooLargeException | Document exceeds 20 MB | Split document |
AuthenticationFailureException | Wrong credentials | Fix credentials โ do not retry |
Error handling by language
If the user is working in a specific language, hand off to the matching sdk-patterns-<lang> skill for deeper patterns (CAS loops, bulk error handling, retry helpers).
Node.js
const couchbase = require('couchbase');
try {
const result = await collection.get('user::alice');
} catch (e) {
if (e instanceof couchbase.DocumentNotFoundError) {
console.log('Document does not exist');
} else if (e instanceof couchbase.CasMismatchError) {
console.log('Concurrent modification โ retry');
} else if (e instanceof couchbase.UnambiguousTimeoutError) {
console.log('Timed out before sending โ retry');
} else if (e instanceof couchbase.AmbiguousTimeoutError) {
console.log('Timed out after sending โ check state');
} else {
throw e;
}
}
Python
from couchbase.exceptions import (
DocumentNotFoundException, CasMismatchException,
UnambiguousTimeoutException, AmbiguousTimeoutException,
DurabilityImpossibleException
)
try:
result = collection.get('user::alice')
except DocumentNotFoundException:
print('Not found')
except CasMismatchException:
print('CAS mismatch โ retry')
except UnambiguousTimeoutException:
print('Timed out before sending โ retry')
except AmbiguousTimeoutException:
print('Timed out after sending โ check state')
Java
import com.couchbase.client.core.error.*;
try {
GetResult result = collection.get("user::alice");
} catch (DocumentNotFoundException e) {
System.out.println("Not found");
} catch (CasMismatchException e) {
System.out.println("CAS mismatch โ retry");
} catch (UnambiguousTimeoutException e) {
System.out.println("Timed out before sending โ retry");
} catch (AmbiguousTimeoutException e) {
System.out.println("Timed out after sending โ check state");
}
Go
import (
"errors"
"github.com/couchbase/gocb/v2"
)
_, err := col.Get("user::alice", nil)
if err != nil {
if errors.Is(err, gocb.ErrDocumentNotFound) {
} else if errors.Is(err, gocb.ErrCasMismatch) {
} else if errors.Is(err, gocb.ErrUnambiguousTimeout) {
} else if errors.Is(err, gocb.ErrAmbiguousTimeout) {
}
}
.NET
using Couchbase.Core.Exceptions;
using Couchbase.Core.Exceptions.KeyValue;
try {
var result = await collection.GetAsync("user::alice");
} catch (DocumentNotFoundException) {
Console.WriteLine("Not found");
} catch (CasMismatchException) {
Console.WriteLine("CAS mismatch โ retry");
} catch (UnambiguousTimeoutException) {
Console.WriteLine("Timed out before sending โ retry");
} catch (AmbiguousTimeoutException) {
Console.WriteLine("Timed out after sending โ check state");
}
Rust
use couchbase::error::ErrorKind;
match collection.get("user::alice", None).await {
Ok(result) => {
}
Err(e) => match e.kind() {
ErrorKind::DocumentNotFound => {
println!("Not found");
}
ErrorKind::DocumentExists => {
println!("Already exists");
}
ErrorKind::CasMismatch => {
println!("CAS mismatch, retry");
}
ErrorKind::ServerTimeout => {
println!("Timed out");
}
_ => return Err(e.into()),
},
}
Retry with exponential backoff
Only retry on the explicit timeout or temporary failure kinds for the SDK you are using. For Rust, ServerTimeout is the main timeout classification exposed by the SDK for document operations.
async function withRetry(fn, maxAttempts = 3, baseDelayMs = 100) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (e) {
const retryable =
e instanceof couchbase.UnambiguousTimeoutError ||
e instanceof couchbase.TemporaryFailureError;
if (!retryable || attempt === maxAttempts) throw e;
const delay = baseDelayMs * Math.pow(2, attempt - 1);
await new Promise(r => setTimeout(r, delay));
}
}
}
For language-specific retry helpers and CAS retry loops, load the matching sdk-patterns-<lang> skill.
Enable SDK debug logging
When you can't tell why connections are failing, enable verbose logging:
process.env.COUCHBASE_LOG_LEVEL = 'debug';
import logging
logging.basicConfig(level=logging.DEBUG)
export COUCHBASE_LOG_LEVEL=debug
sdk-doctor โ diagnose connectivity
When the SDK can't connect and you don't know why, run sdk-doctor:
chmod +x sdk-doctor
./sdk-doctor diagnose couchbase://localhost/travel-sample \
-u Administrator -p "$CB_ADMIN_PASSWORD"
./sdk-doctor diagnose couchbases://cb.<cluster-id>.cloud.couchbase.com/travel-sample \
-u db-user -p db-password
sdk-doctor checks: DNS resolution, TCP connectivity to all ports, TLS certificate validity, CCCP bootstrap, and KV connectivity. It reports exactly which step fails.
Timeout tuning
Default timeouts are conservative. The logical timeout names are the same across all SDKs:
| Timeout | Default | Covers |
|---|
connectTimeout | 10 s | Initial TCP + TLS + auth + topology fetch |
kvTimeout | 2.5 s | Single KV operation (get, upsert, etc.) |
queryTimeout | 75 s | SQL++ query execution |
searchTimeout | 75 s | FTS / vector search |
analyticsTimeout | 75 s | Analytics (CBAS / columnar) query |
For Capella or WAN connections, use the built-in WAN development profile rather than tuning individual timeouts โ it sets all values to safe WAN defaults in one call. The profile is available in all SDKs:
- Node.js:
configProfile: 'wanDevelopment'
- Python:
cluster_options.apply_profile("wan_development")
- Java:
ClusterEnvironment.builder().applyProfile("wan_development")
- Go:
gocb.ClusterOptions{}.ApplyProfile(gocb.ClusterConfigProfileWanDevelopment)
- .NET:
options.ApplyProfile("wan_development")
For language-specific timeout configuration code, load the matching server-connection-<lang> skill.