windmill-labs/windmill · error

file only applies to multi-file apps; ${entry.kind} "${path}

Error message

file only applies to multi-file apps; ${entry.kind} "${path}" diffs as a single document — call again without file.

What it means

Mirror of error 412 for the fork-comparison path: the `file` argument only applies to multi-file apps. When the fork diff entry has no `files` map (single-document kind, or only_in_fork/only_in_parent content dumps without file granularity), passing `file` throws this corrective error telling the caller to retry without it.

Source

Thrown at frontend/src/lib/components/copilot/chat/global/core.ts:7041

	const changedFileCount = entry.files ? Object.keys(entry.files).length : 0
	if (entry.status === 'unchanged' || (!entry.patch && changedFileCount === 0)) {
		// A masked value can differ in content without producing a patch —
		// never report that as "same content".
		const message = entry.valueMasked
			? `${entry.kind} "${path}": no visible config differences vs parent "${parent}", but variable values are never shown in chat, so a value change cannot be displayed. The workspace comparison reports it as ${entry.ahead > 0 || entry.behind > 0 ? `differing (ahead ${entry.ahead}, behind ${entry.behind})` : 'in sync'}.`
			: entry.kind === 'folder'
				? `folder "${path}": no comparable differences vs parent "${parent}" — the folder display name is not exposed by the API and may be what differs (comparison reports ahead ${entry.ahead}, behind ${entry.behind}).`
				: `${entry.kind} "${path}" has the same content in the fork and its parent "${parent}" (only version history differs).`
		return draftCaveat + message
	}
	const header =
		entry.status === 'only_in_fork'
			? `${entry.kind} "${path}" exists only in the fork — not in parent "${parent}". Full content:\n\n`
			: entry.status === 'only_in_parent'
				? `${entry.kind} "${path}" exists only in parent "${parent}" — not in the fork. Parent content:\n\n`
				: `Fork changes vs parent "${parent}" for ${entry.kind} "${path}":\n\n`
	if (args.file !== undefined && !entry.files) {
		throw new Error(
			`file only applies to multi-file apps; ${entry.kind} "${path}" diffs as a single document — call again without file.`
		)
	}
	const body = entry.files
		? renderEntryFiles(entry.files, entry.patch ?? '', args)
		: windowPatchBody(entry.patch ?? '', args.offset ?? 0, args.limit ?? DIFF_READ_DEFAULT_LINES)
	return draftCaveat + header + body
}

const DIFF_SEARCH_DEFAULT_MAX_MATCHES = 50
const DIFF_SEARCH_MAX_MATCHES_CEILING = 200

interface DiffSearchUnit {
	/** Item path, or `${itemPath}/${fileName}` for a file inside an app. */
	subject: string
	patch: string
}

View on GitHub (pinned to e474e8803c)

Solutions

  1. Retry without the `file` argument
  2. For multi-file apps, verify the entry exposes files (type 'app'/'raw_app' with a computed comparison) before narrowing

Example fix

// before
diffFork({ type: 'script', path: 'f/build', file: 'main.ts' })
// after
diffFork({ type: 'script', path: 'f/build' })
Defensive patterns

Strategy: validation

Validate before calling

if (args.file !== undefined && entry.files === undefined) {
  // single-document fork diff: drop file before calling
  delete args.file
}

Type guard

function entryHasFiles(entry: { files?: Record<string, unknown> }): boolean {
  return entry.files !== undefined
}

Try / catch

try {
  return await diffFork(args)
} catch (e) {
  if (String(e?.message).startsWith('file only applies to multi-file apps')) {
    return await diffFork({ ...args, file: undefined })
  }
  throw e
}

Prevention

When it happens

Trigger: Calling the fork diff tool with `args.file` set while `entry.files` is undefined — e.g. diffing a script or a flow against the parent, or an only_in_fork item whose full content is returned as a single document.

Common situations: Agents reusing the `file` argument across calls after diffing an app; assuming parent-side apps always expose file granularity (older comparison data may not include files).

Related errors


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