connector-writer/destination/step-by-step/7-troubleshooting.md
Summary: Quick reference guide for common errors encountered during connector development. Jump here when you hit a problem, find your error, and get back to coding.
Why this section matters: Tests pass but Docker fails? This section explains the three different DI contexts your connector runs in.
Your connector runs in 3 different dependency injection contexts, each with different catalog loading and bean requirements:
Annotation: @MicronautTest(environments = ["component"])
What it is:
Catalog: MockDestinationCatalog
Database: Testcontainers
Tests that run here:
What this catches:
What this DOESN'T catch:
No special annotation - spawns actual connector process
What it is:
Catalog: REAL catalog from JSON
Tests that run here:
What this catches:
What this DOESN'T catch:
How it runs: docker run airbyte/destination-{db}:0.1.0 --write
What it is:
Catalog: REAL catalog from platform
Configuration: application-connector.yml
Common failure: Tests pass, Docker fails
Phase 2-5: TableOperationsSuite (component tests)
↓ Validates: Database operations work
✓ Fast feedback
Phase 6: Name generators created
↓ Enables: TableCatalog instantiation
Phase 7: WriteInitializationTest (integration test)
↓ Validates: Write operation can initialize with REAL catalog
✓ Catches: Missing name generators, WriteOperationV2, bean registrations
Phase 8: ConnectorWiringSuite (component tests)
↓ Validates: Full write path with MOCK catalog
✓ Fast iteration on business logic
Phase 8+: BasicFunctionalityIntegrationTest
↓ Validates: End-to-end with REAL catalog
✓ Full connector functionality
Best practice: Run BOTH
# Fast iteration (component tests)
$ ./gradlew :destination-{db}:componentTest
# Full validation (integration tests)
$ ./gradlew :destination-{db}:integrationTest
Quick troubleshooting guide for the most common Dependency Injection errors
What it means:
Fix: Create name generators (Phase 6)
File: config/{DB}NameGenerators.kt
@Singleton
class {DB}FinalTableNameGenerator(...) : FinalTableNameGenerator { ... }
@Singleton
class {DB}RawTableNameGenerator(...) : RawTableNameGenerator { ... }
@Singleton
class {DB}ColumnNameGenerator : ColumnNameGenerator { ... }
Also register in BeanFactory:
@Singleton
fun tempTableNameGenerator(...): TempTableNameGenerator { ... }
What it means:
Fix: Add bean registration (Phase 7, Step 7.3)
File: {DB}BeanFactory.kt
@Singleton
fun initialStatusGatherer(
client: TableOperationsClient,
tempTableNameGenerator: TempTableNameGenerator,
): DatabaseInitialStatusGatherer<DirectLoadInitialStatus> {
return {DB}DirectLoadDatabaseInitialStatusGatherer(client, tempTableNameGenerator)
}
What it means:
Fix: Create WriteOperationV2 (Phase 7, Step 7.1)
File: cdk/WriteOperationV2.kt
@Primary
@Singleton
@Requires(property = Operation.PROPERTY, value = "write")
class WriteOperationV2(private val d: DestinationLifecycle) : Operation {
override fun execute() { d.run() }
}
What it means:
Fix: Create application-connector.yml (Phase 0, Step 0.8)
File: src/main/resources/application-connector.yml
airbyte:
destination:
core:
data-channel:
medium: STDIO
format: JSONL
mappers:
namespace-mapping-config-path: ""
What it means:
Fix: Make Writer defensive (Phase 8, Step 8.5)
val initialStatus = if (::initialStatuses.isInitialized) {
initialStatuses[stream] ?: DirectLoadInitialStatus(null, null)
} else {
DirectLoadInitialStatus(null, null)
}
Jump here when:
Return to phase guides when: