invoke-ai/InvokeAI · error · ValueError
source_url must be a string
Error message
source_url must be a string
What it means
validate_source_url is a Pydantic before-validator on the model-install/source_url field of model record schemas. If a value is provided for source_url it must be a string; passing any other type raises this ValueError during model record construction/validation.
Source
Thrown at invokeai/app/services/model_records/model_records_base.py:102
tags: Set[str] = Field(description="tags associated with model")
class ModelRecordChanges(BaseModelExcludeNull):
"""A set of changes to apply to a model."""
# Changes applicable to all models
source: Optional[str] = Field(description="original source of the model", default=None)
source_type: Optional[ModelSourceType] = Field(description="type of model source", default=None)
source_api_response: Optional[str] = Field(description="metadata from remote source", default=None)
source_url: Optional[str] = Field(description="Optional URL for the model (e.g. download page)", default=None)
@field_validator("source_url", mode="before")
@classmethod
def validate_source_url(cls, v: Any) -> Optional[str]:
if v is None or v == "":
return None
if not isinstance(v, str):
raise ValueError("source_url must be a string")
if not v.startswith(("https://", "http://")):
raise ValueError("source_url must be an http or https URL")
return v
name: Optional[str] = Field(description="Name of the model.", default=None)
path: Optional[str] = Field(description="Path to the model.", default=None)
description: Optional[str] = Field(description="Model description", default=None)
base: Optional[BaseModelType] = Field(description="The base model.", default=None)
type: Optional[ModelType] = Field(description="Type of model", default=None)
key: Optional[str] = Field(description="Database ID for this model", default=None)
hash: Optional[str] = Field(description="hash of model file", default=None)
file_size: Optional[int] = Field(description="Size of model file", default=None)
format: Optional[str] = Field(description="format of model file", default=None)
trigger_phrases: Optional[set[str]] = Field(description="Set of trigger phrases for this model", default=None)
default_settings: Optional[
MainModelDefaultSettings
| LoraModelDefaultSettings
| ControlAdapterDefaultSettingsView on GitHub (pinned to 0b6a024f2f)
Solutions
- Coerce the value to a plain string before submission (str(url)).
- Ensure API clients serialize URLs as strings in JSON payloads.
- Fix form/deserialization code so URL fields round-trip as strings.
- If empty is intended, send null or "" rather than a non-string.
Example fix
// before
const payload = { source_url: new URL('https://huggingface.co/org/repo') };
// after
const payload = { source_url: 'https://huggingface.co/org/repo' }; Defensive patterns
Strategy: type-guard
Validate before calling
const sourceUrl: unknown = payload.source_url;
if (sourceUrl != null && sourceUrl !== '' && typeof sourceUrl !== 'string') {
throw new TypeError('source_url must be a string');
} Type guard
function isStringUrl(v: unknown): v is string {
return v === null || v === '' || typeof v === 'string';
} Try / catch
try {
await api.addModelRecord(payload);
} catch (e) {
if (String(e).includes('source_url must be a string')) {
payload.source_url = String(payload.source_url ?? '');
return api.addModelRecord(payload);
}
throw e;
} Prevention
- Always serialize URL fields as plain strings in JSON
- Convert URL/AnyHttpUrl/Path objects with str() or .toString() before submitting
- Add client-side schema validation mirroring the server rules
When it happens
Trigger: Constructing a model install/record payload where source_url is a URL object, Path, int, dict, or parsed URL instance instead of a plain string, e.g. source_url: new URL(...) or an AnyHttpUrl object from a previous parse.
Common situations: JavaScript/TypeScript clients passing URL objects; Python callers passing pydantic AnyHttpUrl/Url instances or pathlib.Path instead of str; deserialized YAML/JSON where a resolver produced a non-string mapping.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- source_url must be an http or https URL
- stop must be greater than start
- cfg_scale must be greater than 1
- Face IDs must be a comma-separated list of integers (e.g. "1
- Unsupported cfg_scale type: {type(cfg_scale)}
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/20143658a218cb0c.
Report an issue: GitHub.