windmill-labs/windmill · error · Error

Invalid image object${typeof resolvedConfig.source}

Error message

Invalid image object${typeof resolvedConfig.source}

What it means

AppImage.svelte's loadImage() resolves the image component's configuration source. After trying configured resource/URL resolution, it accepts only a string source; if resolvedConfig.source is truthy but not a string (e.g. an object), it throws 'Invalid image object<type>' to signal a malformed app component configuration.

Source

Thrown at frontend/src/lib/components/apps/components/display/AppImage.svelte:63

	let imageUrl: string | undefined = $state(undefined)

	let token = getContext<{ token?: string }>('AuthToken')

	async function loadImage() {
		if (isPartialS3Object(resolvedConfig.source)) {
			imageUrl = await getS3File({
				source: resolvedConfig.source.s3,
				storage: resolvedConfig.source.storage,
				presigned: resolvedConfig.source.presigned,
				appPath: $appPath,
				username: $userStore?.username,
				workspace,
				token: token?.token,
				isEditor,
				configuration
			})
		} else if (resolvedConfig.source && typeof resolvedConfig.source !== 'string') {
			throw new Error('Invalid image object' + typeof resolvedConfig.source)
		} else if (
			resolvedConfig.sourceKind === 's3 (workspace storage)' ||
			resolvedConfig.source?.startsWith('s3://')
		) {
			imageUrl = await getS3File({
				source: resolvedConfig.source?.replace('s3://', ''),
				appPath: $appPath,
				username: $userStore?.username,
				workspace,
				token: token?.token,
				isEditor,
				configuration
			})
		} else if (resolvedConfig.sourceKind === 'png encoded as base64') {
			imageUrl = 'data:image/png;base64,' + resolvedConfig.source
		} else if (resolvedConfig.sourceKind === 'jpeg encoded as base64') {
			imageUrl = 'data:image/jpeg;base64,' + resolvedConfig.source
		} else if (resolvedConfig.sourceKind === 'svg encoded as base64') {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Inspect the component's source config in the app editor and make it resolve to a string (e.g. append .url or .path to the bound step output)
  2. If the value comes from a variable/step output, stringify the URL at the producing step
  3. Use the resource-based branch (configured resource or s3:// string) instead of passing a raw object

Example fix

// before
source: `${inputs1.result}` // resolves to an object
// after
source: `${inputs1.result.url}`
Defensive patterns

Strategy: validation

Validate before calling

const src = resolvedConfig.source
if (src && typeof src !== 'string') {
  throw new TypeError(`Image source must be a string URL, got ${typeof src}`)
}

Type guard

function isStringSource(s: unknown): s is string {
  return typeof s === 'string'
}

Try / catch

try {
  await loadImage()
} catch (e) {
  if (e.message.startsWith('Invalid image object')) {
    console.error('Fix image component source: it resolved to a non-string', e)
  } else throw e
}

Prevention

When it happens

Trigger: A windmill app image component whose 'source' configuration field (possibly template-resolved via configuration) evaluates to an object or array instead of a URL string.

Common situations: Binding the image source to a step output that returns an object (e.g. {url: ...}) instead of a string; forgetting to append .url/.path on a JSON result; a misconfigured resource template resolving to structured data.

Related errors


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