{"record":{"id":"20143658a218cb0c","repo":"invoke-ai/InvokeAI","slug":"source-url-must-be-a-string","errorCode":null,"errorMessage":"source_url must be a string","messagePattern":"source_url must be a string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/model_records/model_records_base.py","lineNumber":102,"sourceCode":"    tags: Set[str] = Field(description=\"tags associated with model\")\n\n\nclass ModelRecordChanges(BaseModelExcludeNull):\n    \"\"\"A set of changes to apply to a model.\"\"\"\n\n    # Changes applicable to all models\n    source: Optional[str] = Field(description=\"original source of the model\", default=None)\n    source_type: Optional[ModelSourceType] = Field(description=\"type of model source\", default=None)\n    source_api_response: Optional[str] = Field(description=\"metadata from remote source\", default=None)\n    source_url: Optional[str] = Field(description=\"Optional URL for the model (e.g. download page)\", default=None)\n\n    @field_validator(\"source_url\", mode=\"before\")\n    @classmethod\n    def validate_source_url(cls, v: Any) -> Optional[str]:\n        if v is None or v == \"\":\n            return None\n        if not isinstance(v, str):\n            raise ValueError(\"source_url must be a string\")\n        if not v.startswith((\"https://\", \"http://\")):\n            raise ValueError(\"source_url must be an http or https URL\")\n        return v\n\n    name: Optional[str] = Field(description=\"Name of the model.\", default=None)\n    path: Optional[str] = Field(description=\"Path to the model.\", default=None)\n    description: Optional[str] = Field(description=\"Model description\", default=None)\n    base: Optional[BaseModelType] = Field(description=\"The base model.\", default=None)\n    type: Optional[ModelType] = Field(description=\"Type of model\", default=None)\n    key: Optional[str] = Field(description=\"Database ID for this model\", default=None)\n    hash: Optional[str] = Field(description=\"hash of model file\", default=None)\n    file_size: Optional[int] = Field(description=\"Size of model file\", default=None)\n    format: Optional[str] = Field(description=\"format of model file\", default=None)\n    trigger_phrases: Optional[set[str]] = Field(description=\"Set of trigger phrases for this model\", default=None)\n    default_settings: Optional[\n        MainModelDefaultSettings\n        | LoraModelDefaultSettings\n        | ControlAdapterDefaultSettings","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/model_records/model_records_base.py#L84-L120","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst payload = { source_url: new URL('https://huggingface.co/org/repo') };\n// after\nconst payload = { source_url: 'https://huggingface.co/org/repo' };","handlingStrategy":"type-guard","validationCode":"const sourceUrl: unknown = payload.source_url;\nif (sourceUrl != null && sourceUrl !== '' && typeof sourceUrl !== 'string') {\n  throw new TypeError('source_url must be a string');\n}","typeGuard":"function isStringUrl(v: unknown): v is string {\n  return v === null || v === '' || typeof v === 'string';\n}","tryCatchPattern":"try {\n  await api.addModelRecord(payload);\n} catch (e) {\n  if (String(e).includes('source_url must be a string')) {\n    payload.source_url = String(payload.source_url ?? '');\n    return api.addModelRecord(payload);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["pydantic","validation","type-error","model-records"],"backgroundTag":"schema-validation-failed","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}