CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-dev-langchain4j--langchain4j-chroma

LangChain4j integration for Chroma embedding store enabling storage, retrieval, and similarity search of vector embeddings with metadata filtering support for both API V1 and V2.

Pending
Overview
Eval results
Files

error-handling.mddocs/guides/

Error Handling Guide

Comprehensive guide to handling errors when using ChromaEmbeddingStore.

Common Exception Types

Connection Errors

try {
    ChromaEmbeddingStore store = ChromaEmbeddingStore.builder()
        .baseUrl("http://localhost:8000")
        .build();

    store.add(embedding);

} catch (java.net.http.HttpConnectTimeoutException e) {
    // Cannot connect to Chroma server
    System.err.println("Connection failed: " + e.getMessage());
    // Action: Check server is running, verify baseUrl

} catch (java.net.ConnectException e) {
    // Connection refused
    System.err.println("Connection refused: " + e.getMessage());
    // Action: Ensure Chroma server is started
}

Timeout Errors

try {
    EmbeddingSearchResult<TextSegment> result = store.search(request);

} catch (java.net.http.HttpTimeoutException e) {
    // Operation exceeded timeout
    System.err.println("Operation timed out: " + e.getMessage());
    // Action: Increase timeout or reduce operation size
}

Configuration Errors

try {
    ChromaEmbeddingStore store = ChromaEmbeddingStore.builder()
        // Missing baseUrl
        .collectionName("test")
        .build();

} catch (IllegalArgumentException e) {
    // Invalid configuration
    System.err.println("Configuration error: " + e.getMessage());
    // Action: Fix configuration
}

Error Handling Patterns

Basic Try-Catch

public void addDocument(Embedding embedding, TextSegment segment) {
    try {
        store.add(embedding, segment);
    } catch (Exception e) {
        System.err.println("Failed to add document: " + e.getMessage());
        e.printStackTrace();
    }
}

Retry Logic

public String addWithRetry(
    Embedding embedding,
    TextSegment segment,
    int maxRetries
) {
    int attempt = 0;
    Exception lastException = null;

    while (attempt < maxRetries) {
        try {
            return store.add(embedding, segment);

        } catch (java.net.http.HttpTimeoutException |
                 java.net.http.HttpConnectTimeoutException e) {
            lastException = e;
            attempt++;

            if (attempt < maxRetries) {
                System.out.println("Retry " + attempt + " of " + maxRetries);
                try {
                    Thread.sleep(1000 * attempt);  // Exponential backoff
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("Interrupted during retry", ie);
                }
            }

        } catch (Exception e) {
            // Non-retryable error
            throw new RuntimeException("Failed to add document", e);
        }
    }

    throw new RuntimeException(
        "Failed after " + maxRetries + " attempts",
        lastException
    );
}

Circuit Breaker Pattern

public class CircuitBreakerStore {

    private final ChromaEmbeddingStore store;
    private int failureCount = 0;
    private long lastFailureTime = 0;
    private static final int FAILURE_THRESHOLD = 5;
    private static final long RESET_TIMEOUT = 60000;  // 1 minute

    private boolean isCircuitOpen() {
        if (failureCount >= FAILURE_THRESHOLD) {
            long timeSinceFailure = System.currentTimeMillis() - lastFailureTime;
            if (timeSinceFailure < RESET_TIMEOUT) {
                return true;  // Circuit still open
            } else {
                // Try to reset
                failureCount = 0;
                return false;
            }
        }
        return false;
    }

    public String add(Embedding embedding, TextSegment segment) {
        if (isCircuitOpen()) {
            throw new RuntimeException("Circuit breaker is open");
        }

        try {
            String id = store.add(embedding, segment);
            failureCount = 0;  // Reset on success
            return id;

        } catch (Exception e) {
            failureCount++;
            lastFailureTime = System.currentTimeMillis();
            throw e;
        }
    }
}

Graceful Degradation

public class ResilientRAG {

    private final ChromaEmbeddingStore primaryStore;
    private final ChromaEmbeddingStore backupStore;  // Optional backup

    public EmbeddingSearchResult<TextSegment> search(
        EmbeddingSearchRequest request
    ) {
        try {
            return primaryStore.search(request);

        } catch (Exception e) {
            System.err.println("Primary store failed: " + e.getMessage());

            if (backupStore != null) {
                try {
                    System.out.println("Trying backup store");
                    return backupStore.search(request);
                } catch (Exception backupError) {
                    System.err.println("Backup store also failed");
                }
            }

            // Return empty result instead of throwing
            return new EmbeddingSearchResult<>(Collections.emptyList());
        }
    }
}

Specific Error Scenarios

Dimension Mismatch

try {
    // First embedding: 3 dimensions
    store.add(Embedding.from(new float[]{0.1f, 0.2f, 0.3f}));

    // Second embedding: 4 dimensions (will fail)
    store.add(Embedding.from(new float[]{0.1f, 0.2f, 0.3f, 0.4f}));

} catch (RuntimeException e) {
    if (e.getMessage().contains("dimension")) {
        System.err.println("Embedding dimension mismatch");
        // Action: Ensure all embeddings have same dimensions
    }
}

Prevention:

public class EmbeddingValidator {

    private Integer expectedDimension = null;

    public void validateAndAdd(Embedding embedding) {
        int dimension = embedding.vector().length;

        if (expectedDimension == null) {
            expectedDimension = dimension;
        } else if (dimension != expectedDimension) {
            throw new IllegalArgumentException(
                "Expected dimension " + expectedDimension +
                " but got " + dimension
            );
        }

        store.add(embedding);
    }
}

Invalid Filter Errors

try {
    // Invalid: comparison operator on string
    Filter filter = metadataKey("name").isGreaterThan("M");

    EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
        .queryEmbedding(queryEmbedding)
        .filter(filter)
        .build();

    store.search(request);

} catch (RuntimeException e) {
    System.err.println("Invalid filter: " + e.getMessage());
    // Action: Use isEqualTo or isIn for string values
}

Prevention:

// For strings, use equality or collection filters
Filter validFilter = metadataKey("name").isEqualTo("Smith");
Filter validFilter2 = metadataKey("name").isIn(names);

// For numbers, comparison operators work
Filter numericFilter = metadataKey("year").isGreaterThan(2020);

Collection/Server Errors

try {
    store.search(request);

} catch (RuntimeException e) {
    String message = e.getMessage().toLowerCase();

    if (message.contains("collection")) {
        System.err.println("Collection error: " + e.getMessage());
        // Collection may have been deleted or corrupted

    } else if (message.contains("404") || message.contains("not found")) {
        System.err.println("Resource not found: " + e.getMessage());

    } else if (message.contains("500") || message.contains("internal server")) {
        System.err.println("Chroma server error: " + e.getMessage());
        // Check Chroma server logs

    } else {
        System.err.println("Unknown error: " + e.getMessage());
    }
}

Batch Operation Error Handling

Partial Failure Handling

public class BatchProcessor {

    public List<String> addAllWithErrorHandling(
        List<Embedding> embeddings,
        List<TextSegment> segments
    ) {
        try {
            return store.addAll(embeddings, segments);

        } catch (Exception e) {
            System.err.println("Batch add failed: " + e.getMessage());

            // Fallback: add individually to identify failures
            List<String> ids = new ArrayList<>();
            for (int i = 0; i < embeddings.size(); i++) {
                try {
                    String id = store.add(embeddings.get(i), segments.get(i));
                    ids.add(id);
                } catch (Exception itemError) {
                    System.err.println("Failed item " + i + ": " +
                                     itemError.getMessage());
                    ids.add(null);  // Mark failure
                }
            }
            return ids;
        }
    }
}

Chunked Batch Processing

public void addAllInChunks(
    List<Embedding> embeddings,
    List<TextSegment> segments,
    int chunkSize
) {
    for (int i = 0; i < embeddings.size(); i += chunkSize) {
        int end = Math.min(i + chunkSize, embeddings.size());

        try {
            List<Embedding> embBatch = embeddings.subList(i, end);
            List<TextSegment> segBatch = segments.subList(i, end);

            store.addAll(embBatch, segBatch);
            System.out.println("Processed chunk " + (i / chunkSize + 1));

        } catch (Exception e) {
            System.err.println("Chunk " + (i / chunkSize + 1) +
                             " failed: " + e.getMessage());
            // Continue with next chunk or handle failure
        }
    }
}

Logging and Monitoring

Structured Error Logging

public class MonitoredStore {

    private final ChromaEmbeddingStore store;
    private final Logger logger;

    public String add(Embedding embedding, TextSegment segment) {
        long startTime = System.currentTimeMillis();

        try {
            String id = store.add(embedding, segment);
            long duration = System.currentTimeMillis() - startTime;

            logger.info("Add successful - duration: {}ms", duration);
            return id;

        } catch (java.net.http.HttpTimeoutException e) {
            long duration = System.currentTimeMillis() - startTime;
            logger.error("Add timeout after {}ms: {}", duration, e.getMessage());
            throw e;

        } catch (Exception e) {
            logger.error("Add failed: {}", e.getMessage(), e);
            throw e;
        }
    }
}

Metrics Collection

public class MetricsStore {

    private final AtomicLong successCount = new AtomicLong();
    private final AtomicLong failureCount = new AtomicLong();
    private final AtomicLong totalDuration = new AtomicLong();

    public String addWithMetrics(Embedding embedding, TextSegment segment) {
        long start = System.currentTimeMillis();

        try {
            String id = store.add(embedding, segment);
            successCount.incrementAndGet();
            totalDuration.addAndGet(System.currentTimeMillis() - start);
            return id;

        } catch (Exception e) {
            failureCount.incrementAndGet();
            throw e;
        }
    }

    public void printMetrics() {
        long success = successCount.get();
        long failure = failureCount.get();
        long total = success + failure;
        long avgDuration = total > 0 ? totalDuration.get() / success : 0;

        System.out.println("Success: " + success);
        System.out.println("Failure: " + failure);
        System.out.println("Success rate: " +
                         (total > 0 ? (success * 100.0 / total) : 0) + "%");
        System.out.println("Avg duration: " + avgDuration + "ms");
    }
}

Testing Error Conditions

Simulating Errors

@Test
public void testConnectionError() {
    // Use invalid URL to test connection error handling
    ChromaEmbeddingStore store = ChromaEmbeddingStore.builder()
        .baseUrl("http://invalid-host:9999")
        .timeout(Duration.ofSeconds(1))
        .build();

    assertThrows(Exception.class, () -> {
        store.add(Embedding.from(new float[]{1.0f, 0.0f, 0.0f}));
    });
}

@Test
public void testTimeoutError() {
    ChromaEmbeddingStore store = ChromaEmbeddingStore.builder()
        .baseUrl("http://localhost:8000")
        .timeout(Duration.ofMillis(1))  // Very short timeout
        .build();

    // May timeout with large operations
    List<Embedding> largeList = generateLargeEmbeddingList();

    assertThrows(java.net.http.HttpTimeoutException.class, () -> {
        store.addAll(largeList);
    });
}

Best Practices

  1. Always handle exceptions - Network operations can fail
  2. Use specific exception types - Catch specific exceptions first
  3. Implement retry logic - For transient failures
  4. Log errors comprehensively - Include context and stack traces
  5. Monitor error rates - Track and alert on high failure rates
  6. Test error conditions - Verify error handling works
  7. Provide fallbacks - Degrade gracefully when possible
  8. Validate input early - Catch errors before sending to server
  9. Set appropriate timeouts - Balance between reliability and responsiveness
  10. Document error scenarios - Help users understand failures

Related

  • Configuration Guide - Proper configuration
  • Performance Guide - Timeout tuning
  • ChromaEmbeddingStore API - Method signatures

External Resources

  • LangChain4j Error Handling
  • Chroma Troubleshooting

Install with Tessl CLI

npx tessl i tessl/maven-dev-langchain4j--langchain4j-chroma

docs

index.md

tile.json