Error Handling
Kodio uses a sealed class hierarchy for errors, so you can write exhaustive when expressions and catch missing cases at compile time.
Error types
All errors extend AudioError:
- PermissionDenied
User denied microphone access. Prompt them to enable it in settings.
- DeviceNotFound
No microphone or speaker available. Common on simulators or headless systems.
- FormatNotSupported
The requested audio format isn't supported on this platform.
- DeviceError
Hardware-level failure during recording or playback.
- NotInitialized
Android only: Kodio.initialize(context) wasn't called before recording.
- AlreadyRecording
Attempted to start recording when a recording is already in progress.
- AlreadyPlaying
Attempted to start playback when audio is already playing.
- NoRecordingData
Called getRecording() before any audio was recorded.
- Unknown
Unexpected error. Check the cause property for details.
Handling errors
Use try-catch with pattern matching:
try {
val recording = Kodio.record(duration = 5.seconds)
} catch (e: AudioError) {
when (e) {
is AudioError.PermissionDenied -> {
// Request permission
Kodio.microphonePermission.request()
}
is AudioError.DeviceNotFound -> {
showError("No microphone found")
}
is AudioError.NotInitialized -> {
// Android: forgot to initialize
showError("Call Kodio.initialize() first")
}
is AudioError.AlreadyRecording -> {
// Ignore or stop current recording
}
else -> {
showError(e.message ?: "Recording failed")
}
}
}
In Compose
RecorderState and PlayerState expose errors via the error property:
val recorderState = rememberRecorderState()
// Show error dialog
recorderState.error?.let { error ->
AlertDialog(
onDismissRequest = { recorderState.clearError() },
title = { Text("Recording Error") },
text = {
Text(when (error) {
is AudioError.PermissionDenied ->
"Microphone access is required. Please enable it in settings."
is AudioError.DeviceNotFound ->
"No microphone detected."
else ->
error.message ?: "An error occurred"
})
},
confirmButton = {
TextButton(onClick = { recorderState.clearError() }) {
Text("OK")
}
}
)
}
Permission flow
The most common error is PermissionDenied. Here's a complete permission handling flow:
@Composable
fun RecorderWithPermissionFlow() {
val recorderState = rememberRecorderState()
var showSettings by remember { mutableStateOf(false) }
when {
recorderState.needsPermission -> {
// First time: request permission
PermissionPrompt(
onRequest = { recorderState.requestPermission() }
)
}
recorderState.error is AudioError.PermissionDenied -> {
// Denied: suggest settings
PermissionDeniedPrompt(
onOpenSettings = { showSettings = true },
onDismiss = { recorderState.clearError() }
)
}
else -> {
// Ready to record
RecorderUI(recorderState)
}
}
}
Error reference
Error | Cause | Solution |
|---|
PermissionDenied
| User denied access | Request permission or guide to settings |
DeviceNotFound
| No audio hardware | Check device capabilities |
NotInitialized
| Missing init call | Call Kodio.initialize(context) on Android |
AlreadyRecording
| Concurrent recording | Stop current recording first |
AlreadyPlaying
| Concurrent playback | Stop current playback first |
FormatNotSupported
| Invalid format | Use supported format or preset |
NoRecordingData
| Empty recording | Record before calling getRecording() |
DeviceError
| Hardware failure | Retry or report to user |
Unknown
| Unexpected error | Log and report |
Last modified: 27 June 2026