Describe the bug
We encountered a JVM class initialization deadlock in the AWS Bedrock Kotlin SDK related to the GuardrailContentSource model. We had this problem in our unit tests which runs in parallel and a bunch of Bedrock requests being created.
Summary
Concurrent access to GuardrailContentSource and its nested Output object can lead to a JVM class initialization deadlock. This appears to be caused by circular initialization dependencies between the outer sealed class and its nested singleton objects.
Affected Code
public sealed class GuardrailContentSource {
public abstract val value: String
public object Input : GuardrailContentSource() { ... }
public object Output : GuardrailContentSource() { ... }
public companion object {
public fun fromValue(value: String): GuardrailContentSource = when (value) {
"INPUT" -> Input
"OUTPUT" -> Output
else -> SdkUnknown(value)
}
private val values: List<GuardrailContentSource> = listOf(
Input,
Output,
)
}
}
Root Cause
- Kotlin object declarations are compiled into separate JVM classes with their own class initialization locks.
- The companion object eagerly initializes values, which references both Input and Output.
- At the same time, fromValue("OUTPUT") or other code paths may directly trigger initialization of Output.
This allows two threads to initialize classes in opposite order:
Thread A
- Initializes GuardrailContentSource (holds its class init lock)
- During companion init, tries to initialize Output
Thread B
- Initializes Output (holds its class init lock)
- Requires GuardrailContentSource to be initialized first
This results in a classic circular wait:
- Thread A waits for Output
- Thread B waits for GuardrailContentSource
Observed Behavior
- Application hangs indefinitely during concurrent access
- Thread dump shows threads blocked on class initialization monitors ()
Impact
This can affect any multithreaded application using the Bedrock Kotlin SDK where these model classes are accessed concurrently, especially under high concurrency or during cold start.
Regression Issue
Expected behavior
We don't have deadlock.
Current behavior
We have deadlock when running tests in a bunch. I assume it also could happen in production services when you run concurrent requests and get unlucky with clinit order. Would be extremely hard to investigate.
Steps to Reproduce
With simple test example
// Mirrors GuardrailContentSource from aws.sdk.kotlin:bedrockruntime.
// Its companion eagerly references subclass singletons — the source of the circular dependency.
private sealed class GuardrailContentSourceSim {
companion object {
val values: List<GuardrailContentSourceSim> = listOf(Input, Output)
fun values(): List<GuardrailContentSourceSim> = values
}
object Input : GuardrailContentSourceSim()
object Output : GuardrailContentSourceSim()
}
@Execution(ExecutionMode.CONCURRENT)
class MethodLevelParallelDeadlockTest {
// Group 1: access via companion — triggers GuardrailContentSourceSim.<clinit>
@Test fun testValues1() { assertNotNull(GuardrailContentSourceSim.values()) }
@Test fun testValues2() { assertNotNull(GuardrailContentSourceSim.values()) }
@Test fun testValues3() { assertNotNull(GuardrailContentSourceSim.values()) }
// Group 2: access subclass directly — triggers Output.<clinit>,
// which requires GuardrailContentSourceSim (its superclass) to be initialized first
@Test fun testOutput1() { assertNotNull(GuardrailContentSourceSim.Output) }
@Test fun testOutput2() { assertNotNull(GuardrailContentSourceSim.Output) }
@Test fun testOutput3() { assertNotNull(GuardrailContentSourceSim.Output) }
}
Possible Solution
No response
Context
We resolved the issue locally by forcing initialization of values before all tests run - https://github.com/JetBrains/koog/pull/1788/changes
AWS SDK for Kotlin version
1.6.17
Platform (JVM/JS/Native)
JVM
Operating system and version
macOS Tahoe 26.1
Describe the bug
We encountered a JVM class initialization deadlock in the AWS Bedrock Kotlin SDK related to the GuardrailContentSource model. We had this problem in our unit tests which runs in parallel and a bunch of Bedrock requests being created.
Summary
Concurrent access to GuardrailContentSource and its nested Output object can lead to a JVM class initialization deadlock. This appears to be caused by circular initialization dependencies between the outer sealed class and its nested singleton objects.
Affected Code
Root Cause
This allows two threads to initialize classes in opposite order:
Thread A
Thread B
This results in a classic circular wait:
Observed Behavior
Impact
This can affect any multithreaded application using the Bedrock Kotlin SDK where these model classes are accessed concurrently, especially under high concurrency or during cold start.
Regression Issue
Expected behavior
We don't have deadlock.
Current behavior
We have deadlock when running tests in a bunch. I assume it also could happen in production services when you run concurrent requests and get unlucky with clinit order. Would be extremely hard to investigate.
Steps to Reproduce
With simple test example
Possible Solution
No response
Context
We resolved the issue locally by forcing initialization of values before all tests run - https://github.com/JetBrains/koog/pull/1788/changes
AWS SDK for Kotlin version
1.6.17
Platform (JVM/JS/Native)
JVM
Operating system and version
macOS Tahoe 26.1