windmill-labs/windmill · error · Error
Invalid source object${typeof resolvedConfig.source}
Error message
Invalid source object${typeof resolvedConfig.source} What it means
AppDownload resolves its configured `source` into a downloadable URL. A string source (including s3:// paths) is supported, but if the resolved config yields a non-string, non-falsy source object the component throws, since it has no way to turn an object into a download URL.
Source
Thrown at frontend/src/lib/components/apps/components/display/AppDownload.svelte:93
)
}
}
async function loadSource() {
if (isPartialS3Object(resolvedConfig.source)) {
downloadUrl = 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 source object' + typeof resolvedConfig.source)
} else if (resolvedConfig.source?.startsWith('s3://')) {
downloadUrl = await getS3File({
source: resolvedConfig.source?.replace('s3://', ''),
appPath: $appPath,
username: $userStore?.username,
workspace,
token: token?.token,
isEditor,
configuration
})
} else {
downloadUrl = transformBareBase64IfNecessary(resolvedConfig.source)
}
}
let css = $state(initCss($app.css?.downloadcomponent, untrack(() => customCss)))
$effect(() => {
resolvedConfig.beforeIcon && beforeIconComponent && untrack(() => handleBeforeIcon())View on GitHub (pinned to e474e8803c)
Solutions
- Change the component's source configuration so it evaluates to a string URL (or s3:// path)
- Inspect what the bound expression returns — stringify it or select the URL field of the returned object
- If using a script to produce the source, return `url` as a plain string
Example fix
// before source: myScriptResult // object // after source: myScriptResult.url // string, e.g. 'https://.../file.pdf' or 's3://bucket/key'
Defensive patterns
Strategy: type-guard
Validate before calling
if (resolvedConfig.source && typeof resolvedConfig.source !== 'string') {
throw new Error(`source must be a string URL or s3:// path, got ${typeof resolvedConfig.source}`)
} Type guard
function isDownloadSource(s: unknown): s is string {
return typeof s === 'string' && s.length > 0
} Try / catch
try {
await loadSource()
} catch (e) {
if (String(e.message).startsWith('Invalid source object')) {
downloadError = 'Configure the download source as a string URL'
} else throw e
} Prevention
- Ensure bound expressions/script outputs for `source` return strings, not objects
- Use input templates that interpolate to URL strings
- Validate component configuration in the app editor before publishing
When it happens
Trigger: The app's download component configuration resolves `source` to an object (e.g. a evaluated/templated expression returning an object, or a misconfigured resource binding) — neither undefined nor a string — so loadSource hits the `typeof !== 'string'` branch.
Common situations: Binding the source field to a script/flow output that returns an object instead of a URL string; using an input template that interpolates into an object; a configuration left half-migrated between source formats.
Related errors
- ${what} failed:\n${output}
- No instance found, please add one first
- No local instance profile named ${instanceName}
- No active instance. Run 'wmill instance add' or pass --insta
- Active instance ${activeName} not found in config
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/70ad58edc92030a3.
Report an issue: GitHub.