Troubleshooting
A reference for the exceptions Ariadne throws and recipes for the most common runtime problems.
Exception reference
Every Ariadne-specific exception extends AriadneException, so you can catch the whole family with a single handler. (Argument-validation errors still surface as the standard JDK IllegalArgumentException — those indicate programmer mistakes, not runtime failures.)
import dev.cjfravel.ariadne.exceptions._
try {
index.update
} catch {
case e: AriadneException => // handle any Ariadne error
}
| Exception | When it's thrown |
|---|---|
SchemaNotProvidedException | Creating a new index without a schema. |
SchemaMismatchException | Source schema changed and allowSchemaMismatch is false. |
FormatMismatchException | Format passed at construction doesn't match what's stored. |
IndexNotFoundException | Removing or referencing an index that doesn't exist. |
IndexNotFoundInNewSchemaException | New schema is missing a previously indexed column. |
ColumnNotFoundException | Referencing a column that's not in the schema or indexes. |
IndexLockException | Lock acquisition timed out (default 1 hr). |
MetadataMissingOrCorruptException | Index metadata is unreadable — delete and re-create. |
MissingFormatException | Creating a new index without a format. |
MissingSchemaException | Schema field is null in metadata (corrupted file). |
SchemaParseException | Stored schema string can't be parsed. |
FileListNotFoundException | Removing a file list that doesn't exist. |
UnsupportedStorageFormatVersionException | The index declares a newer storage_format_version than this Ariadne build supports. |
UnsupportedMetadataVersionException | The index declares a newer metadata_version than this Ariadne build supports. |
UnsupportedJoinTypeException | The requested join type depends on unmatched index-side rows — see Supported join types. |
Persisted-index compatibility
This Ariadne build supports indexes created by 0.0.1-alpha-37 through 0.1.10-beta. Queries and other operational methods migrate supported older layouts under the update lock; plain Index(name) construction remains read-only. Indexes written by later releases may require a newer library.
| Failure | Recovery |
|---|---|
UnsupportedStorageFormatVersionException or UnsupportedMetadataVersionException | Upgrade Ariadne to a version that supports the declared storage_format_version or metadata_version. Do not downgrade or edit version markers manually. |
Index predates 0.0.1-alpha-37 | Remove and rebuild the index from source data with the current library. |
| Migration fails physical verification | Correct the reported missing source, filesystem, or schema problem and retry. The version is not advanced on failure. |
| Metadata is corrupt or a previously indexed column was removed | Restore a known-good index directory or remove and rebuild from source. |
Ariadne does not silently rebuild, downgrade, or return incomplete query results when it encounters an unsupported or unverifiable layout.
FetchFailedException during joins
Large indexes can produce enormous intermediate DataFrames during the array explode step, which overwhelms Spark's shuffle. Spread the work across more partitions:
spark.conf.set("spark.ariadne.indexRepartitionCount", "500")
// If your data files are also very large
spark.conf.set("spark.ariadne.repartitionDataFiles", "true")
Typical values for indexRepartitionCount: 100–500, depending on cluster size and data volume. Don't set it for small indexes — the extra shuffle hurts more than it helps.
IndexLockException
Two causes:
- Another job is legitimately holding the lock. Wait for it to finish.
- A previous job crashed mid-operation and left a stale lock.
Stale locks auto-heal after spark.ariadne.lockTimeout seconds (default 30 min). If you're certain no job is running and don't want to wait, delete the lock file directly:
{storagePath}/{indexName}/.update.lock
{storagePath}/{indexName}/.filelist.lock
Don't delete locks blindly. If you nuke a lock while a job is actually holding it, two writers will race and you'll get corrupted Delta state. Confirm no job is running first.
Out-of-memory during update
High-cardinality columns produce large in-memory arrays during the build phase. Two levers:
-
Lower the large-index threshold so high-cardinality columns get split into separate Delta tables earlier:
spark.conf.set("spark.ariadne.largeIndexLimit", "100000") -
Switch to bloom indexes for the offending column — a bloom filter is sized from that file's own distinct count (roughly 1.2 bytes per distinct value at the default 1% FPR), so memory stays proportional to cardinality rather than growing with the full value array:
index.addBloomIndex("high_cardinality_col", fpr = 0.01)
MetadataMissingOrCorruptException
The metadata.json file for the index is missing or unparseable. There's no in-place repair — remove and rebuild:
Index.remove("myIndex")
val index = Index("myIndex", schema, "parquet")
// re-add indexes and files, then update
SchemaMismatchException
Your source data schema changed since the index was built. Reconnect with the new schema and opt in to the mismatch:
val index = Index("myIndex", newSchema, "parquet", allowSchemaMismatch = true)
Caveat: all previously indexed columns must still exist in the new schema. If a column was renamed or removed, you'll get IndexNotFoundInNewSchemaException and need to remove and rebuild.
Joins log 0% pruning
The pruning-metrics line shows loaded N of N files — every file was read. Common causes:
- You're not joining on an indexed column. Check
index.indexesand confirm the join key is in the set. - Your join type isn't optimizable. Pruning runs for every accepted join type, so this is no longer a cause on its own — but join types that depend on unmatched index rows (
full_outer, andleft_anti/leftorrightdepending on direction) are now rejected outright withUnsupportedJoinTypeException. See Supported join types. - Through the SQL catalog: not an INNER equi-join. Catalyst only pre-prunes for INNER equi-joins on same-name fully-indexed columns. Other shapes fall back to full scan.
- Every file genuinely contains every key. If your data is small or your keys are very common, there's nothing to prune.
Enable debug logging for a per-stage breakdown:
spark.conf.set("spark.ariadne.debug", "true")