windmill-labs/windmill · warning

failed to read ${kind} ${path} in ${workspace}

Error message

failed to read ${kind} ${path} in ${workspace}

What it means

Thrown by diffSnapshot.ts when reading the server-side value of an item to build a diff snapshot and the read comes back empty (null or an empty object). getItemValue resolves to {} for ANY failed fetch, including 'item may not exist', but for a fork side that the comparison says exists, an empty read must be a transient failure — so the code throws instead of fabricating a misleading one-sided or matching diff. The throw is surfaced as a fetch-error entry in the diff result.

Source

Thrown at frontend/src/lib/components/copilot/chat/global/diffSnapshot.ts:975

	if (kind === 'resource_type') {
		const rt = await ResourceService.getResourceType({ workspace, path })
		return {
			value: {
				schema: rt.schema,
				description: rt.description,
				format_extension: rt.format_extension,
				is_fileset: rt.is_fileset
			},
			valueMasked: false
		}
	}
	const value = await getItemValue(kind as DeployKind, path, workspace)
	// getItemValue reads `{}` for ANY failed fetch ("item may not exist") — but
	// a fork side is only fetched when the comparison lists it as existing, so
	// an empty read is a transient failure. Erroring (surfaced as a fetch-error
	// entry) beats fabricating a one-sided or matching diff out of it.
	if (value == null || (typeof value === 'object' && Object.keys(value).length === 0)) {
		throw new Error(`failed to read ${kind} ${path} in ${workspace}`)
	}
	if ((kind === 'app' || kind === 'raw_app') && value !== null && typeof value === 'object') {
		const row = value as Record<string, unknown>
		// Raw apps: project onto the flat files/runnables draft shape so per-file
		// splitting works and the sides match the draft-mode canonicalization.
		// parent_version is a per-workspace version counter — never comparable
		// across workspaces. Inline-script locks are server-recomputed noise.
		if (kind === 'raw_app' || row.raw_app === true) {
			const canonical = appSourceToDraftValue(row) as Record<string, unknown>
			delete canonical.parent_version
			const runnables = canonical.runnables as Record<string, any> | undefined
			if (runnables) {
				for (const k of Object.keys(runnables)) {
					if (runnables[k]?.inlineScript?.lock != undefined) {
						runnables[k].inlineScript.lock = undefined
					}
				}
			}

View on GitHub (pinned to e474e8803c)

Solutions

  1. Retry the diff — the error is documented as a transient-failure guard, so a re-run after the hiccup usually succeeds.
  2. Verify the item still exists in the source workspace and the fork is up to date (re-sync the fork).
  3. Check permissions/network for the workspace being read, then retry.

Example fix

// before (transient empty read kills the diff)
await diffSnapshot(...) // Error: failed to read script f/etl in fork-ws

// after: retry with backoff
try { await diffSnapshot(...) } catch { await sleep(1000); await diffSnapshot(...) }
Defensive patterns

Strategy: retry

Validate before calling

const exists = await itemExistsInListing(kind, path, workspace)
if (!exists) {
  throw new Error(`${kind} ${path} not listed in ${workspace}; skip diff`)
}

Type guard

function isEmptyRead(v) {
  return v == null || (typeof v === 'object' && Object.keys(v).length === 0)
}

Try / catch

try {
  await diffSnapshot(...)
} catch (e) {
  if (/^failed to read /.test(e.message)) {
    await sleep(1000)
    return diffSnapshot(...) // transient; retry once
  }
  throw e
}

Prevention

When it happens

Trigger: Building a workspace/fork diff when getItemValue(kind, path, workspace) returns null or an empty object for a side that the comparison listing says exists — network hiccup, permission error, or a race where the item was deleted between listing and reading.

Common situations: Diffing against a fork right after it was created (eventual consistency); the upstream item was deleted server-side between the list call and the read; a token/permission issue scoped to the fork workspace; temporary backend 5xx.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/b03742c83f848b87. Report an issue: GitHub.