apple/pkl · error · DocGeneratorBugException

Error deserializing `${path.toUri()}`.

Error message

Error deserializing `${path.toUri()}`.

What it means

RuntimeData.readOrEmpty reads cached runtime data from a JSON file and deserializes it. A missing file is treated as empty, but a kotlinx SerializationException (the file exists yet cannot be parsed into the expected schema) is wrapped in a DocGeneratorBugException with the file URI in the message.

Source

Thrown at pkl-doc/src/main/kotlin/org/pkl/doc/RuntimeData.kt:76

            if (comparison != 0) return@Comparator comparison
          } catch (_: Throwable) {
            // possibly happens if the version is invalid.
            continue
          }
        }
        0
      }
    }

    fun readOrEmpty(path: Path): RuntimeData {
      return try {
        json.decodeFromString(path.readString())
      } catch (e: Throwable) {
        when (e) {
          is NoSuchFileException,
          is FileNotFoundException -> EMPTY
          is SerializationException ->
            throw DocGeneratorBugException("Error deserializing `${path.toUri()}`.", e)
          else -> throw e
        }
      }
    }
  }

  fun <T : ElementRef<*>> addKnownVersions(
    myRef: T,
    versions: Set<String>?,
    comparator: Comparator<String>,
  ): RuntimeData {
    if (versions == null) return this
    val newEffectiveVersions = knownVersions.mapTo(mutableSetOf()) { it.text } + versions
    val knownVersions =
      newEffectiveVersions
        .sortedWith(comparator)
        .map { version -> RuntimeDataLink(text = version, href = myRef.pageUrlForVersion(version)) }
        .toSet()

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Delete the cached data file so it is regenerated from scratch.
  2. Ensure the cache was written by the same pkl-doc version now reading it.
  3. Validate the JSON structure against the expected RuntimeData schema.
  4. Check the wrapped SerializationException message for the exact field/type mismatch.

Example fix

// before
val data = RuntimeData.readOrEmpty(staleCachePath) // SerializationException
// after
staleCachePath.deleteIfExists() // regenerate cache on version upgrade
val data = RuntimeData.readOrEmpty(staleCachePath)
Defensive patterns

Strategy: validation

Validate before calling

val f = File(cachePath)
if (f.exists()) runCatching { Json.decodeFromString<RuntimeData>(f.readText()) }.onFailure { f.delete() }

Try / catch

try { RuntimeData.readOrEmpty(path) } catch (e: DocGeneratorBugException) { Files.deleteIfExists(path); RuntimeData.readOrEmpty(path) }

Prevention

When it happens

Trigger: Calling readOrEmpty when the file at `path` exists but contains JSON that fails to deserialize into the expected @Serializable type (corrupt cache, schema mismatch between generator versions).

Common situations: Stale or hand-edited cache files, a pkl-doc version upgrade changing the cached data schema, truncated file from a previous crashed run.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/deeff0138f56e26a. Report an issue: GitHub.