@@ -223,7 +223,7 @@ def _load_external_models(
223223 if external_models_path .exists () and external_models_path .is_dir ():
224224 paths_to_load .extend (self ._glob_paths (external_models_path , extension = ".yaml" ))
225225
226- def _load () -> t .List [Model ]:
226+ def _load (path : Path ) -> t .List [Model ]:
227227 try :
228228 with open (path , "r" , encoding = "utf-8" ) as file :
229229 return [
@@ -241,21 +241,30 @@ def _load() -> t.List[Model]:
241241 for row in YAML ().load (file .read ())
242242 ]
243243 except Exception as ex :
244- raise ConfigError (f"Failed to load model definition at '{ path } '.\n { ex } " )
244+ self ._raise_failed_to_load_model_error (path , str (ex ))
245+ raise
245246
246247 for path in paths_to_load :
247248 self ._track_file (path )
248249
249- external_models = cache .get_or_load_models (path , _load )
250+ external_models = cache .get_or_load_models (path , lambda : _load ( path ) )
250251 # external models with no explicit gateway defined form the base set
251252 for model in external_models :
252253 if model .gateway is None :
254+ if model .fqn in models :
255+ self ._raise_failed_to_load_model_error (
256+ path , f"Duplicate external model name: '{ model .name } '."
257+ )
253258 models [model .fqn ] = model
254259
255260 # however, if there is a gateway defined, gateway-specific models take precedence
256261 if gateway :
257262 for model in external_models :
258263 if model .gateway == gateway :
264+ if model .fqn in models and models [model .fqn ].gateway == gateway :
265+ self ._raise_failed_to_load_model_error (
266+ path , f"Duplicate external model name: '{ model .name } '."
267+ )
259268 models .update ({model .fqn : model })
260269
261270 return models
@@ -363,6 +372,9 @@ def _get_variables(self, gateway_name: t.Optional[str] = None) -> t.Dict[str, t.
363372
364373 return self ._variables_by_gateway [gateway_name ]
365374
375+ def _raise_failed_to_load_model_error (self , path : Path , message : str ) -> None :
376+ raise ConfigError (f"Failed to load model definition at '{ path } '.\n { message } " )
377+
366378
367379class SqlMeshLoader (Loader ):
368380 """Loads macros and models for a context using the SQLMesh file formats"""
@@ -484,9 +496,14 @@ def _load() -> t.List[Model]:
484496 default_catalog_per_gateway = self .context .default_catalog_per_gateway ,
485497 )
486498 except Exception as ex :
487- raise ConfigError (f"Failed to load model definition at '{ path } '.\n { ex } " )
499+ self ._raise_failed_to_load_model_error (path , str (ex ))
500+ raise
488501
489502 for model in cache .get_or_load_models (path , _load ):
503+ if model .fqn in models :
504+ self ._raise_failed_to_load_model_error (
505+ path , f"Duplicate SQL model name: '{ model .name } '."
506+ )
490507 if model .enabled :
491508 models [model .fqn ] = model
492509
@@ -544,7 +561,7 @@ def _load_python_models(
544561 if model .enabled :
545562 models [model .fqn ] = model
546563 except Exception as ex :
547- raise ConfigError ( f"Failed to load model definition at ' { path } '. \n { ex } " )
564+ self . _raise_failed_to_load_model_error ( path , str ( ex ) )
548565
549566 finally :
550567 model_registry ._dialect = None
0 commit comments