tauri-apps/tauri · error · JSONException
Not all items are instances of the given type
Error message
Not all items are instances of the given type
What it means
The Kotlin `JSArray.toList<E>()` extension casts each JSONArray element to `E`; if any element is not an instance of the requested type, it throws a `JSONException` with this message. It protects Android plugin IPC from receiving arrays of unexpected element types.
Solutions
- Inspect the plugin command signature in the Kotlin handler and send exactly that element type from JS/Rust.
- Remove null/undefined entries from the array before invoking (e.g. `args.filter(a => a != null)`).
- If the plugin API changed, update both the Kotlin plugin and the frontend bindings to the same version.
- Catch `JSONException` on the Kotlin side (or use `opt(i)`/manual conversion) if you need tolerant parsing.
Example fix
// before
invoke('plugin:fs|read', { paths: [null, '/a.txt'] })
// after
invoke('plugin:fs|read', { paths: ['/a.txt'] }) // all elements match handler's List<String> Defensive patterns
Strategy: type-guard
Validate before calling
function assertStringArray(arr) {
if (!Array.isArray(arr) || arr.some(a => typeof a !== 'string'))
throw new TypeError('expected array of strings');
} Type guard
function isStringArray(v) {
return Array.isArray(v) && v.every(x => typeof x === 'string');
} Try / catch
// Kotlin side, tolerant parse
val items = try { arr.toList<String>() } catch (e: JSONException) { emptyList() } Prevention
- Match JS argument element types to the Kotlin handler's declared types
- Filter out null/undefined before invoking
- Keep plugin and frontend bindings versions in sync
When it happens
Trigger: Invoking an Android plugin command whose JS argument array contains elements that cannot be cast to the Kotlin type declared by the handler (e.g. sending objects where the handler expects strings, or nulls).
Common situations: JS/Rust side passing mixed-type arrays, nulls, or nested objects to plugin commands; plugin signature changed after an upgrade while frontend still sends the old argument shape.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- No command found for plugin
- unexpected channel value $channelDef
- failed to serialize scope
- the plugin manager has no activity to launch from
- Android folder already exists
AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18).
Data as JSON: /api/errors/b4f2fa05f6847634.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tauri/mobile/android/src/main/java/app/tauri/plugin/JSArray.kt:26
import org.json.JSONException
class JSArray : JSONArray {
constructor() : super() {}
constructor(json: String?) : super(json) {}
constructor(copyFrom: Collection<*>?) : super(copyFrom) {}
constructor(array: Any?) : super(array) {}
@Suppress("UNCHECKED_CAST", "ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
@Throws(JSONException::class)
fun <E> toList(): List<E> {
val items: MutableList<E> = ArrayList()
var o: Any? = null
for (i in 0 until this.length()) {
this.get(i).also { o = it }
try {
items.add(this.get(i) as E)
} catch (ex: Exception) {
throw JSONException("Not all items are instances of the given type")
}
}
return items
}
companion object {
/**
* Create a new JSArray without throwing a error
*/
fun from(array: Any?): JSArray? {
try {
return JSArray(array)
} catch (ex: JSONException) {
//
}
return null
}
}View on GitHub (pinned to 460ec35447)