Repository: astropy/astroquery
Pull request #3292: Pass in resolver name to MAST query functions
Author: login: snbianco
Labels: name: mast
Created: 2025-04-16T02:36:12Z | Merged: 2025-04-28T15:56:04Z

This PR adds a `resolver` parameter to various MAST query functions. This parameter allows users to specify what resolver they want to use when resolving object names into coordinates.

It also adds `resolver` and `resolve_all` parameters to the `resolve_object` function. If `resolve_all` is `True`, then `resolve_object` will return a dictionary where keys are resolver names and values are their resolved coordinates.

I added test cases and updated our documentation to reflect these additions.

Also fixes some test failures brought on by numpy 2.0 changes and closes #3299 

Linked issue #3299: BUG: MAST TypeErrors for fill values
I see several errors: `ValueError: invalid literal for int() with base 10: 'N/A'` when running the mast remote tests (use: `pytest -P mast -R`). If `N/A` is coming out of the server it should definitely handled inside the module. 

cc @snbianco 
Linked issue comments: user: login: snbianco
created_at: 2025-04-24T01:56:35Z
body: I can't reproduce these errors, and I'm not 100% sure what server call might return "N/A". Do you still have the logs from the test run?
author_association: CONTRIBUTOR
user: login: ManonMarchand
created_at: 2025-04-24T07:33:11Z
body: I got bitten by this not long ago. Astropy's VOtable parser became more strict in the last versions. Maybe you need to upgrade to reproduce?
author_association: MEMBER
user: login: bsipocz
created_at: 2025-04-24T15:22:43Z
body: Yes, I tend to use dev versions locally, but there is also a traceback in the CI jobs e.g. here: https://github.com/astropy/astroquery/actions/runs/14413478820/job/40426160902#step:5:29172
author_association: MEMBER
user: login: snbianco
created_at: 2025-04-25T00:24:41Z
body: Ahh, I needed to upgrade numpy. Thanks for the tip, @ManonMarchand!

These were small fixes, so I pushed them to #3292 
author_association: CONTRIBUTOR

Diff:
diff --git a/CHANGES.rst b/CHANGES.rst
index 6971af3077..9eff47458a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -43,6 +43,14 @@ utils.tap
 - The method ``upload_table`` accepts file formats accepted by astropy's
   ``Table.read()``. [#3295]
 
+mast
+^^^^
+
+- Added ``resolver`` parameter to query methods to specify the resolver to use when resolving object names to coordinates. [#3292]
+
+- Added ``resolve_all`` parameter to ``MastClass.resolve_object`` to resolve object names and return 
+  coordinates for all available resolvers. [#3292]
+
 
 Infrastructure, Utility and Other Changes and Additions
 -------------------------------------------------------
diff --git a/astroquery/mast/collections.py b/astroquery/mast/collections.py
index 3eea6eb806..bd14943a9c 100644
--- a/astroquery/mast/collections.py
+++ b/astroquery/mast/collections.py
@@ -294,7 +294,7 @@ def query_region_async(self, coordinates, *, radius=0.2*u.deg, catalog="Hsc",
 
     @class_or_instance
     def query_object_async(self, objectname, *, radius=0.2*u.deg, catalog="Hsc",
-                           pagesize=None, page=None, version=None, **criteria):
+                           pagesize=None, page=None, version=None, resolver=None, **criteria):
         """
         Given an object name, returns a list of catalog entries.
         See column documentation for specific catalogs `here <https://mast.stsci.edu/api/v0/pages.html>`__.
@@ -316,11 +316,16 @@ def query_object_async(self, objectname, *, radius=0.2*u.deg, catalog="Hsc",
             Can be used to override the default pagesize for (set in configs) this query only.
             E.g. when using a slow internet connection.
         page : int, optional
-            Defaulte None.
+            Default None.
             Can be used to override the default behavior of all results being returned
             to obtain a specific page of results.
         version : int, optional
             Version number for catalogs that have versions. Default is highest version.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
         **criteria
             Catalog-specific keyword args.
             These can be found in the `service documentation <https://mast.stsci.edu/api/v0/_services.html>`__.
@@ -339,7 +344,7 @@ def query_object_async(self, objectname, *, radius=0.2*u.deg, catalog="Hsc",
         response : list of `~requests.Response`
         """
 
-        coordinates = utils.resolve_object(objectname)
+        coordinates = utils.resolve_object(objectname, resolver=resolver)
 
         return self.query_region_async(coordinates,
                                        radius=radius,
@@ -350,7 +355,7 @@ def query_object_async(self, objectname, *, radius=0.2*u.deg, catalog="Hsc",
                                        **criteria)
 
     @class_or_instance
-    def query_criteria_async(self, catalog, *, pagesize=None, page=None, **criteria):
+    def query_criteria_async(self, catalog, *, pagesize=None, page=None, resolver=None, **criteria):
         """
         Given an set of filters, returns a list of catalog entries.
         See column documentation for specific catalogs `here <https://mast.stsci.edu/api/v0/pages.html>`__.
@@ -365,6 +370,11 @@ def query_criteria_async(self, catalog, *, pagesize=None, page=None, **criteria)
         page : int, optional
             Can be used to override the default behavior of all results being returned to obtain
             one specific page of results.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
         **criteria
             Criteria to apply. At least one non-positional criteria must be supplied.
             Valid criteria are coordinates, objectname, radius (as in `query_region` and `query_object`),
@@ -395,7 +405,9 @@ def query_criteria_async(self, catalog, *, pagesize=None, page=None, **criteria)
         radius = criteria.pop('radius', 0.2*u.deg)
 
         if objectname or coordinates:
-            coordinates = utils.parse_input_location(coordinates, objectname)
+            coordinates = utils.parse_input_location(coordinates=coordinates,
+                                                     objectname=objectname,
+                                                     resolver=resolver)
 
         # if radius is just a number we assume degrees
         radius = coord.Angle(radius, u.deg)
diff --git a/astroquery/mast/core.py b/astroquery/mast/core.py
index d68de05559..16e0759512 100644
--- a/astroquery/mast/core.py
+++ b/astroquery/mast/core.py
@@ -110,7 +110,7 @@ def disable_cloud_dataset(self):
         """
         pass
 
-    def resolve_object(self, objectname):
+    def resolve_object(self, objectname, *, resolver=None, resolve_all=False):
         """
         Resolves an object name to a position on the sky.
 
@@ -118,10 +118,23 @@ def resolve_object(self, objectname):
         ----------
         objectname : str
             Name of astronomical object to resolve.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. If ``resolve_all`` is True, this parameter will be ignored. Default is None.
+        resolve_all : bool, optional
+            If True, will try to resolve the object name using all available resolvers ("NED", "SIMBAD").
+            Function will return a dictionary where the keys are the resolver names and the values are the
+            resolved coordinates. Default is False.
 
         Returns
         -------
-        response : `~astropy.coordinates.SkyCoord`
-            The sky position of the given object.
+        response : `~astropy.coordinates.SkyCoord`, dict
+            If ``resolve_all`` is False, returns a `~astropy.coordinates.SkyCoord` object with the resolved coordinates.
+            If ``resolve_all`` is True, returns a dictionary where the keys are the resolver names and the values are
+            `~astropy.coordinates.SkyCoord` objects with the resolved coordinates.
         """
-        return utils.resolve_object(objectname)
+        return utils.resolve_object(objectname,
+                                    resolver=resolver,
+                                    resolve_all=resolve_all)
diff --git a/astroquery/mast/cutouts.py b/astroquery/mast/cutouts.py
index 24186adc59..2da8833dbf 100644
--- a/astroquery/mast/cutouts.py
+++ b/astroquery/mast/cutouts.py
@@ -107,7 +107,7 @@ def __init__(self):
         self._service_api_connection.set_service_params(services, "tesscut")
 
     def get_sectors(self, *, coordinates=None, radius=0*u.deg, product='SPOC', objectname=None,
-                    moving_target=False, mt_type=None):
+                    moving_target=False, mt_type=None, resolver=None):
         """
         Get a list of the TESS data sectors whose footprints intersect
         with the given search area.
@@ -152,6 +152,11 @@ def get_sectors(self, *, coordinates=None, radius=0*u.deg, product='SPOC', objec
             first majorbody is tried and then smallbody if a matching majorbody is not found.
 
             NOTE: If moving_target is supplied, this argument is ignored.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
 
         Returns
         -------
@@ -187,7 +192,9 @@ def get_sectors(self, *, coordinates=None, radius=0*u.deg, product='SPOC', objec
         else:
 
             # Get Skycoord object for coordinates/object
-            coordinates = parse_input_location(coordinates, objectname)
+            coordinates = parse_input_location(coordinates=coordinates,
+                                               objectname=objectname,
+                                               resolver=resolver)
 
             # If radius is just a number we assume degrees
             radius = Angle(radius, u.deg)
@@ -223,7 +230,8 @@ def get_sectors(self, *, coordinates=None, radius=0*u.deg, product='SPOC', objec
         return Table(sector_dict)
 
     def download_cutouts(self, *, coordinates=None, size=5, sector=None, product='SPOC', path=".",
-                         inflate=True, objectname=None, moving_target=False, mt_type=None, verbose=False):
+                         inflate=True, objectname=None, moving_target=False, mt_type=None, resolver=None,
+                         verbose=False):
         """
         Download cutout target pixel file(s) around the given coordinates with indicated size.
 
@@ -280,6 +288,11 @@ def download_cutouts(self, *, coordinates=None, size=5, sector=None, product='SP
             first majorbody is tried and then smallbody if a matching majorbody is not found.
 
             NOTE: If moving_target is supplied, this argument is ignored.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
 
         Returns
         -------
@@ -310,7 +323,9 @@ def download_cutouts(self, *, coordinates=None, size=5, sector=None, product='SP
         else:
 
             # Get Skycoord object for coordinates/object
-            coordinates = parse_input_location(coordinates, objectname)
+            coordinates = parse_input_location(coordinates=coordinates,
+                                               objectname=objectname,
+                                               resolver=resolver)
 
             astrocut_request = f"astrocut?ra={coordinates.ra.deg}&dec={coordinates.dec.deg}"
 
@@ -359,7 +374,7 @@ def download_cutouts(self, *, coordinates=None, size=5, sector=None, product='SP
         return localpath_table
 
     def get_cutouts(self, *, coordinates=None, size=5, product='SPOC', sector=None,
-                    objectname=None, moving_target=False, mt_type=None):
+                    objectname=None, moving_target=False, mt_type=None, resolver=None):
         """
         Get cutout target pixel file(s) around the given coordinates with indicated size,
         and return them as a list of  `~astropy.io.fits.HDUList` objects.
@@ -408,6 +423,11 @@ def get_cutouts(self, *, coordinates=None, size=5, product='SPOC', sector=None,
             first majorbody is tried and then smallbody if a matching majorbody is not found.
 
             NOTE: If moving_target is supplied, this argument is ignored.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
 
         Returns
         -------
@@ -457,7 +477,9 @@ def get_cutouts(self, *, coordinates=None, size=5, product='SPOC', sector=None,
             param_dict['product'] = product.upper()
 
             # Get Skycoord object for coordinates/object
-            coordinates = parse_input_location(coordinates, objectname)
+            coordinates = parse_input_location(coordinates=coordinates,
+                                               objectname=objectname,
+                                               resolver=resolver)
 
             param_dict["ra"] = coordinates.ra.deg
             param_dict["dec"] = coordinates.dec.deg
@@ -531,7 +553,7 @@ def get_surveys(self, coordinates, *, radius="0d"):
         """
 
         # Get Skycoord object for coordinates/object
-        coordinates = parse_input_location(coordinates)
+        coordinates = parse_input_location(coordinates=coordinates)
         radius = Angle(radius, u.deg)
 
         params = {"ra": coordinates.ra.deg,
@@ -596,7 +618,7 @@ def download_cutouts(self, coordinates, *, size=5, survey=None, cutout_format="f
             Cutout file(s) for given coordinates
         """
         # Get Skycoord object for coordinates/object
-        coordinates = parse_input_location(coordinates)
+        coordinates = parse_input_location(coordinates=coordinates)
         size_dict = _parse_cutout_size(size)
 
         path = os.path.join(path, '')
@@ -675,7 +697,7 @@ def get_cutouts(self, coordinates, *, size=5, survey=None):
         """
 
         # Get Skycoord object for coordinates/object
-        coordinates = parse_input_location(coordinates)
+        coordinates = parse_input_location(coordinates=coordinates)
 
         param_dict = _parse_cutout_size(size)
         param_dict["ra"] = coordinates.ra.deg
@@ -760,7 +782,7 @@ def download_cutouts(self, coordinates, *, size=5, path=".", inflate=True, verbo
         """
 
         # Get Skycoord object for coordinates/object
-        coordinates = parse_input_location(coordinates)
+        coordinates = parse_input_location(coordinates=coordinates)
 
         # Build initial astrocut request
         astrocut_request = f"astrocut?ra={coordinates.ra.deg}&dec={coordinates.dec.deg}"
@@ -829,7 +851,7 @@ def get_cutouts(self, coordinates, *, size=5):
         """
 
         # Get Skycoord object for coordinates/object
-        coordinates = parse_input_location(coordinates)
+        coordinates = parse_input_location(coordinates=coordinates)
 
         param_dict = _parse_cutout_size(size)
 
diff --git a/astroquery/mast/missions.py b/astroquery/mast/missions.py
index 02736d218f..91b7f69612 100644
--- a/astroquery/mast/missions.py
+++ b/astroquery/mast/missions.py
@@ -222,7 +222,7 @@ def query_region_async(self, coordinates, *, radius=3*u.arcmin, limit=5000, offs
 
     @class_or_instance
     def query_criteria_async(self, *, coordinates=None, objectname=None, radius=3*u.arcmin,
-                             limit=5000, offset=0, select_cols=None, **criteria):
+                             limit=5000, offset=0, select_cols=None, resolver=None, **criteria):
         """
         Given a set of search criteria, returns a list of mission metadata.
 
@@ -246,6 +246,11 @@ def query_criteria_async(self, *, coordinates=None, objectname=None, radius=3*u.
             the number of records you wish to skip before selecting records.
         select_cols: list, None
             Default None. Names of columns that will be included in the astropy table
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
         **criteria
             Criteria to apply. At least one non-positional criterion must be supplied.
             Valid criteria are coordinates, objectname, radius (as in
@@ -268,7 +273,9 @@ def query_criteria_async(self, *, coordinates=None, objectname=None, radius=3*u.
 
         # Parse user input location
         if objectname or coordinates:
-            coordinates = utils.parse_input_location(coordinates, objectname)
+            coordinates = utils.parse_input_location(coordinates=coordinates,
+                                                     objectname=objectname,
+                                                     resolver=resolver)
 
         # if radius is just a number we assume degrees
         radius = coord.Angle(radius, u.arcmin)
@@ -300,7 +307,7 @@ def query_criteria_async(self, *, coordinates=None, objectname=None, radius=3*u.
 
     @class_or_instance
     def query_object_async(self, objectname, *, radius=3*u.arcmin, limit=5000, offset=0,
-                           select_cols=None, **criteria):
+                           select_cols=None, resolver=None, **criteria):
         """
         Given an object name, returns a list of matching rows.
 
@@ -321,6 +328,11 @@ def query_object_async(self, objectname, *, radius=3*u.arcmin, limit=5000, offse
             the number of records you wish to skip before selecting records.
         select_cols: list, None
             Default None. Names of columns that will be included in the astropy table
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
         **criteria
             Other mission-specific criteria arguments.
             All valid filters can be found using `~astroquery.mast.missions.MastMissionsClass.get_column_list`
@@ -332,7 +344,7 @@ def query_object_async(self, objectname, *, radius=3*u.arcmin, limit=5000, offse
         response : list of `~requests.Response`
         """
 
-        coordinates = utils.resolve_object(objectname)
+        coordinates = utils.resolve_object(objectname, resolver=resolver)
 
         return self.query_region_async(coordinates, radius=radius, limit=limit, offset=offset,
                                        select_cols=select_cols, **criteria)
diff --git a/astroquery/mast/observations.py b/astroquery/mast/observations.py
index 90647f5495..4ed2b46735 100644
--- a/astroquery/mast/observations.py
+++ b/astroquery/mast/observations.py
@@ -119,13 +119,18 @@ def get_metadata(self, query_type):
 
         return self._portal_api_connection._get_columnsconfig_metadata(colconf_name)
 
-    def _parse_caom_criteria(self, **criteria):
+    def _parse_caom_criteria(self, *, resolver=None, **criteria):
         """
         Helper function that takes dictionary of criteria and parses them into
         position (none if there are no coordinates/object name) and a filter set.
 
         Parameters
         ----------
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
         **criteria
             Criteria to apply.
             Valid criteria are coordinates, objectname, radius (as in `query_region` and `query_object`),
@@ -154,7 +159,9 @@ def _parse_caom_criteria(self, **criteria):
             mashup_filters = self._portal_api_connection.build_filter_set(self._caom_cone,
                                                                           self._caom_filtered_position,
                                                                           **criteria)
-            coordinates = utils.parse_input_location(coordinates, objectname)
+            coordinates = utils.parse_input_location(coordinates=coordinates,
+                                                     objectname=objectname,
+                                                     resolver=resolver)
         else:
             mashup_filters = self._portal_api_connection.build_filter_set(self._caom_cone,
                                                                           self._caom_filtered,
@@ -240,7 +247,7 @@ def query_region_async(self, coordinates, *, radius=0.2*u.deg, pagesize=None, pa
         return self._portal_api_connection.service_request_async(service, params, pagesize=pagesize, page=page)
 
     @class_or_instance
-    def query_object_async(self, objectname, *, radius=0.2*u.deg, pagesize=None, page=None):
+    def query_object_async(self, objectname, *, radius=0.2*u.deg, pagesize=None, page=None, resolver=None):
         """
         Given an object name, returns a list of MAST observations.
         See column documentation `here <https://mast.stsci.edu/api/v0/_c_a_o_mfields.html>`__.
@@ -262,18 +269,23 @@ def query_object_async(self, objectname, *, radius=0.2*u.deg, pagesize=None, pag
             Defaulte None.
             Can be used to override the default behavior of all results being returned
             to obtain a specific page of results.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
 
         Returns
         -------
         response : list of `~requests.Response`
         """
 
-        coordinates = utils.resolve_object(objectname)
+        coordinates = utils.resolve_object(objectname, resolver=resolver)
 
         return self.query_region_async(coordinates, radius=radius, pagesize=pagesize, page=page)
 
     @class_or_instance
-    def query_criteria_async(self, *, pagesize=None, page=None, **criteria):
+    def query_criteria_async(self, *, pagesize=None, page=None, resolver=None, **criteria):
         """
         Given an set of criteria, returns a list of MAST observations.
         Valid criteria are returned by ``get_metadata("observations")``
@@ -286,6 +298,11 @@ def query_criteria_async(self, *, pagesize=None, page=None, **criteria):
         page : int, optional
             Can be used to override the default behavior of all results being returned to obtain
             one specific page of results.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
         **criteria
             Criteria to apply. At least one non-positional criteria must be supplied.
             Valid criteria are coordinates, objectname, radius (as in `query_region` and `query_object`),
@@ -303,7 +320,7 @@ def query_criteria_async(self, *, pagesize=None, page=None, **criteria):
         response : list of `~requests.Response`
         """
 
-        position, mashup_filters = self._parse_caom_criteria(**criteria)
+        position, mashup_filters = self._parse_caom_criteria(resolver=resolver, **criteria)
 
         if not mashup_filters:
             raise InvalidQueryError("At least one non-positional criterion must be supplied.")
@@ -361,7 +378,7 @@ def query_region_count(self, coordinates, *, radius=0.2*u.deg, pagesize=None, pa
 
         return int(self._portal_api_connection.service_request(service, params, pagesize, page)[0][0])
 
-    def query_object_count(self, objectname, *, radius=0.2*u.deg, pagesize=None, page=None):
+    def query_object_count(self, objectname, *, radius=0.2*u.deg, pagesize=None, page=None, resolver=None):
         """
         Given an object name, returns the number of MAST observations.
 
@@ -379,17 +396,22 @@ def query_object_count(self, objectname, *, radius=0.2*u.deg, pagesize=None, pag
         page : int, optional
             Can be used to override the default behavior of all results being returned to obtain
             one specific page of results.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
 
         Returns
         -------
         response : int
         """
 
-        coordinates = utils.resolve_object(objectname)
+        coordinates = utils.resolve_object(objectname, resolver=resolver)
 
         return self.query_region_count(coordinates, radius=radius, pagesize=pagesize, page=page)
 
-    def query_criteria_count(self, *, pagesize=None, page=None, **criteria):
+    def query_criteria_count(self, *, pagesize=None, page=None, resolver=None, **criteria):
         """
         Given an set of filters, returns the number of MAST observations meeting those criteria.
 
@@ -401,6 +423,11 @@ def query_criteria_count(self, *, pagesize=None, page=None, **criteria):
         page : int, optional
             Can be used to override the default behavior of all results being returned to obtain
             one specific page of results.
+        resolver : str, optional
+            The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+            If not specified, the default resolver order will be used. Please see the
+            `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+            for more information. Default is None.
         **criteria
             Criteria to apply. At least one non-positional criterion must be supplied.
             Valid criteria are coordinates, objectname, radius (as in `query_region` and `query_object`),
@@ -418,7 +445,7 @@ def query_criteria_count(self, *, pagesize=None, page=None, **criteria):
         response : int
         """
 
-        position, mashup_filters = self._parse_caom_criteria(**criteria)
+        position, mashup_filters = self._parse_caom_criteria(resolver=resolver, **criteria)
 
         # send query
         if position:
diff --git a/astroquery/mast/tests/data/README.rst b/astroquery/mast/tests/data/README.rst
index a99f0123e2..6138c3dac3 100644
--- a/astroquery/mast/tests/data/README.rst
+++ b/astroquery/mast/tests/data/README.rst
@@ -48,3 +48,16 @@ To generate `~astroquery.mast.tests.data.mast_relative_path.json`, use the follo
     ...                              {'uri': ['mast:HST/product/u9o40504m_c3m.fits', 'mast:HST/product/does_not_exist.fits']})
     >>> with open('mast_relative_path.json', 'w') as file:
     ...     json.dump(resp.json(), file, indent=4)  # doctest: +SKIP
+
+
+To generate `~astroquery.mast.tests.data.resolver.json`, use the following:
+
+.. doctest-remote-data::
+
+    >>> import json
+    >>> from astroquery.mast import utils
+    ...
+    >>> resp = utils._simple_request('http://mastresolver.stsci.edu/Santa-war/query',
+    ...                              {'name': 'TIC 307210830', 'outputFormat': 'json', 'resolveAll': 'true'})
+    >>> with open('resolver.json', 'w') as file:
+    ...     json.dump(resp.json(), file, indent=4)  # doctest: +SKIP
diff --git a/astroquery/mast/tests/data/resolver.json b/astroquery/mast/tests/data/resolver.json
index 0133b2eac1..7051c9fc78 100644
--- a/astroquery/mast/tests/data/resolver.json
+++ b/astroquery/mast/tests/data/resolver.json
@@ -1 +1,39 @@
-{"resolvedCoordinate":[{"searchString":"m103","resolver":"NED","cached":true,"resolverTime":114,"cacheDate":"Apr 19, 2017 2:32:38 PM","searchRadius":-1.0,"canonicalName":"MESSIER 103","ra":23.34086,"decl":60.658,"objectType":"*Cl"}],"status":""}
+{
+    "resolvedCoordinate": [
+        {
+            "searchString": "tic 307210830",
+            "resolver": "TIC",
+            "cached": false,
+            "resolverTime": 3,
+            "searchRadius": 0.000333,
+            "canonicalName": "TIC 307210830",
+            "ra": 124.531756290083,
+            "decl": -68.3129998725044
+        },
+        {
+            "searchString": "tic 307210830",
+            "resolver": "SIMBADCFA",
+            "cached": true,
+            "resolverTime": 289,
+            "cacheDate": "Mar 19, 2025, 4:36:27 PM",
+            "searchRadius": -1.0,
+            "canonicalName": "L   98-59",
+            "ra": 124.5317560026638,
+            "decl": -68.3130014904408,
+            "objectType": "HighPM*"
+        },
+        {
+            "searchString": "tic 307210830",
+            "resolver": "SIMBAD",
+            "cached": true,
+            "resolverTime": 299,
+            "cacheDate": "Apr 17, 2025, 3:47:59 PM",
+            "searchRadius": -1.0,
+            "canonicalName": "L   98-59",
+            "ra": 124.5317560026638,
+            "decl": -68.3130014904408,
+            "objectType": "HighPM*"
+        }
+    ],
+    "status": ""
+}
\ No newline at end of file
diff --git a/astroquery/mast/tests/test_mast.py b/astroquery/mast/tests/test_mast.py
index 2cc86acfde..8ebdf5af16 100644
--- a/astroquery/mast/tests/test_mast.py
+++ b/astroquery/mast/tests/test_mast.py
@@ -18,7 +18,7 @@
 from astroquery.mast.services import _json_to_table
 from astroquery.utils.mocks import MockResponse
 from astroquery.exceptions import (InvalidQueryError, InputWarning, MaxResultsWarning, NoResultsWarning,
-                                   RemoteServiceError)
+                                   RemoteServiceError, ResolverError)
 
 from astroquery import mast
 
@@ -141,7 +141,7 @@ def service_mockreturn(self, method="POST", url=None, data=None, params=None, ti
 def request_mockreturn(url, params={}):
     if 'column_list' in url:
         filename = data_path(DATA_FILES['mission_columns'])
-    elif 'Mast.Name.Lookup' in params:
+    elif 'mastresolver' in url:
         filename = data_path(DATA_FILES["Mast.Name.Lookup"])
     elif 'panstarrs' in url:
         filename = data_path(DATA_FILES['panstarrs_columns'])
@@ -492,8 +492,33 @@ def test_mast_query(patch_post):
 
 
 def test_resolve_object(patch_post):
-    m103_loc = mast.Mast.resolve_object("M103")
-    assert round(m103_loc.separation(SkyCoord("23.34086 60.658", unit='deg')).value, 10) == 0
+    obj = "TIC 307210830"
+    tic_coord = SkyCoord(124.531756290083, -68.3129998725044, unit="deg")
+    simbad_coord = SkyCoord(124.5317560026638, -68.3130014904408, unit="deg")
+    obj_loc = mast.Mast.resolve_object(obj)
+    assert round(obj_loc.separation(tic_coord).value, 10) == 0
+
+    # resolve using a specific resolver and an object that belongs to a MAST catalog
+    obj_loc_simbad = mast.Mast.resolve_object(obj, resolver="SIMBAD")
+    assert round(obj_loc_simbad.separation(simbad_coord).value, 10) == 0
+
+    # resolve using a specific resolver and an object that does not belong to a MAST catalog
+    obj_loc_simbad = mast.Mast.resolve_object("M101", resolver="SIMBAD")
+    assert round(obj_loc_simbad.separation(simbad_coord).value, 10) == 0
+
+    # resolve using all resolvers
+    obj_loc_dict = mast.Mast.resolve_object(obj, resolve_all=True)
+    assert isinstance(obj_loc_dict, dict)
+    assert round(obj_loc_dict["SIMBAD"].separation(simbad_coord).value, 10) == 0
+
+    # error with invalid resolver
+    with pytest.raises(ResolverError, match="Invalid resolver"):
+        mast.Mast.resolve_object(obj, resolver="invalid")
+
+    # warn if specifying both resolver and resolve_all
+    with pytest.warns(InputWarning, match="The resolver parameter is ignored when resolve_all is True"):
+        loc = mast.Mast.resolve_object(obj, resolver="NED", resolve_all=True)
+        assert isinstance(loc, dict)
 
 
 def test_login_logout(patch_post):
@@ -1162,3 +1187,37 @@ def test_zcut_get_cutouts(patch_post, tmpdir):
     assert isinstance(cutout_list, list)
     assert len(cutout_list) == 1
     assert isinstance(cutout_list[0], fits.HDUList)
+
+
+################
+# Utils tests #
+################
+
+
+def test_parse_input_location(patch_post):
+    # Test with coordinates
+    coord = SkyCoord(23.34086, 60.658, unit="deg")
+    loc = mast.utils.parse_input_location(coordinates=coord)
+    assert isinstance(loc, SkyCoord)
+    assert loc.ra == coord.ra
+    assert loc.dec == coord.dec
+
+    # Test with object name
+    obj_coord = SkyCoord(124.531756290083, -68.3129998725044, unit="deg")
+    loc = mast.utils.parse_input_location(objectname="TIC 307210830")
+    assert isinstance(loc, SkyCoord)
+    assert loc.ra == obj_coord.ra
+    assert loc.dec == obj_coord.dec
+
+    # Error if both coordinates and object name are provided
+    with pytest.raises(InvalidQueryError, match="Only one of objectname and coordinates may be specified"):
+        mast.utils.parse_input_location(coordinates=coord, objectname="M101")
+
+    # Error if neither coordinates nor object name is provided
+    with pytest.raises(InvalidQueryError, match="One of objectname and coordinates must be specified"):
+        mast.utils.parse_input_location()
+
+    # Warn if resolver is specified without an object name
+    with pytest.warns(InputWarning, match="Resolver is only used when resolving object names"):
+        loc = mast.utils.parse_input_location(coordinates=coord, resolver="SIMBAD")
+        assert isinstance(loc, SkyCoord)
diff --git a/astroquery/mast/tests/test_mast_remote.py b/astroquery/mast/tests/test_mast_remote.py
index cfd452441b..f6a56a8aa7 100644
--- a/astroquery/mast/tests/test_mast_remote.py
+++ b/astroquery/mast/tests/test_mast_remote.py
@@ -32,7 +32,7 @@ def msa_product_table():
     products = Observations.get_product_list(obs['obsid'][0])
 
     # Filter out everything but the MSA config file
-    mask = np.char.find(products["dataURI"], "_msa.fits") != -1
+    mask = np.char.find(np.char.asarray(products["dataURI"]), "_msa.fits") != -1
     products = products[mask]
 
     return products
@@ -52,6 +52,32 @@ def test_resolve_object(self):
         ticobj_loc = utils.resolve_object("TIC 141914082")
         assert round(ticobj_loc.separation(SkyCoord("94.6175354 -72.04484622", unit='deg')).value, 4) == 0
 
+        # Try the same object with different resolvers
+        # The position of objects can change with different resolvers
+        ned_loc = utils.resolve_object("jw100", resolver="NED")
+        assert round(ned_loc.separation(SkyCoord("354.10436 21.15083", unit='deg')).value, 4) == 0
+
+        simbad_loc = utils.resolve_object("jw100", resolver="simbad")
+        assert round(simbad_loc.separation(SkyCoord("83.70341477 -5.55918309", unit="deg")).value, 4) == 0
+
+        # Try an object from a MAST catalog with a resolver
+        catalog_loc = utils.resolve_object("TIC 307210830", resolver="SIMBAD")
+        assert round(catalog_loc.separation(SkyCoord("124.5317560 -68.31300149", unit="deg")).value, 4) == 0
+
+        # Use resolve_all to get all resolvers
+        loc_dict = utils.resolve_object("jw100", resolve_all=True)
+        assert isinstance(loc_dict, dict)
+        assert loc_dict['NED'] == ned_loc
+        assert loc_dict['SIMBAD'] == simbad_loc
+
+        # Error if coordinates cannot be resolved
+        with pytest.raises(ResolverError, match="Could not resolve invalid to a sky position."):
+            utils.resolve_object("invalid")
+
+        # Error if coordinates cannot be resolved with a specific resolver
+        with pytest.raises(ResolverError, match="Could not resolve invalid to a sky position using NED"):
+            utils.resolve_object("invalid", resolver="NED")
+
     ###########################
     # MissionSearchClass Test #
     ###########################
@@ -596,7 +622,7 @@ def test_observations_get_product_list_tess_tica(self, caplog):
 
         # Should only return products corresponding to target 429031146
         assert len(prods) > 0
-        assert (np.char.find(prods['obs_id'], '429031146') != -1).all()
+        assert (np.char.find(np.char.asarray(prods['obs_id']), '429031146') != -1).all()
 
     def test_observations_get_unique_product_list(self, caplog):
         # Check that no rows are filtered out when all products are unique
diff --git a/astroquery/mast/utils.py b/astroquery/mast/utils.py
index 8693c7be60..f160635294 100644
--- a/astroquery/mast/utils.py
+++ b/astroquery/mast/utils.py
@@ -10,20 +10,17 @@
 import numpy as np
 
 import requests
-import json
 import platform
-from urllib import parse
 
-import astropy.coordinates as coord
+from astropy.coordinates import SkyCoord
 from astropy.table import unique, Table
+from astropy import units as u
 
 from .. import log
 from ..version import version
-from ..exceptions import NoResultsWarning, ResolverError, InvalidQueryError
+from ..exceptions import InputWarning, NoResultsWarning, ResolverError, InvalidQueryError
 from ..utils import commons
 
-from . import conf
-
 
 __all__ = []
 
@@ -90,7 +87,7 @@ def _simple_request(url, params=None):
     return response
 
 
-def resolve_object(objectname):
+def resolve_object(objectname, *, resolver=None, resolve_all=False):
     """
     Resolves an object name to a position on the sky.
 
@@ -98,31 +95,105 @@ def resolve_object(objectname):
     ----------
     objectname : str
         Name of astronomical object to resolve.
+    resolver : str, optional
+        The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+        If not specified, the default resolver order will be used. Please see the
+        `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+        for more information. If ``resolve_all`` is True, this parameter will be ignored. Default is None.
+    resolve_all : bool, optional
+        If True, will try to resolve the object name using all available resolvers ("NED", "SIMBAD").
+        Function will return a dictionary where the keys are the resolver names and the values are the
+        resolved coordinates. Default is False.
 
     Returns
     -------
-    response : `~astropy.coordinates.SkyCoord`
-        The sky position of the given object.
+    response : `~astropy.coordinates.SkyCoord`, dict
+        If ``resolve_all`` is False, returns a `~astropy.coordinates.SkyCoord` object with the resolved coordinates.
+        If ``resolve_all`` is True, returns a dictionary where the keys are the resolver names and the values are
+        `~astropy.coordinates.SkyCoord` objects with the resolved coordinates.
     """
-
-    request_args = {"service": "Mast.Name.Lookup",
-                    "params": {'input': objectname, 'format': 'json'}}
-    request_string = 'request={}'.format(parse.quote(json.dumps(request_args)))
-
-    response = _simple_request("{}/api/v0/invoke".format(conf.server), request_string)
-    result = response.json()
-
-    if len(result['resolvedCoordinate']) == 0:
-        raise ResolverError("Could not resolve {} to a sky position.".format(objectname))
-
-    ra = result['resolvedCoordinate'][0]['ra']
-    dec = result['resolvedCoordinate'][0]['decl']
-    coordinates = coord.SkyCoord(ra, dec, unit="deg")
-
-    return coordinates
-
-
-def parse_input_location(coordinates=None, objectname=None):
+    is_catalog = False  # Flag to check if object name belongs to a MAST catalog
+    catalog = None  # Variable to store the catalog name
+    objectname = objectname.strip()
+    catalog_prefixes = {
+        'TIC ': 'TIC',
+        'KIC ': 'KEPLER',
+        'EPIC ': 'K2'
+    }
+
+    if resolver:
+        # Check that resolver is valid
+        resolver = resolver.upper()
+        if resolver not in ('NED', 'SIMBAD'):
+            raise ResolverError('Invalid resolver. Must be "NED" or "SIMBAD".')
+
+        if resolve_all:
+            # Warn if user is trying to use a resolver with resolve_all
+            warnings.warn('The resolver parameter is ignored when resolve_all is True. '
+                          'Coordinates will be resolved using all available resolvers.', InputWarning)
+
+        # Check if object belongs to a MAST catalog
+        for prefix, name in catalog_prefixes.items():
+            if objectname.startswith(prefix):
+                is_catalog = True
+                catalog = name
+                break
+
+    # Whether to set resolveAll to True when making the HTTP request
+    # Should be True when resolve_all = True or when object name belongs to a MAST catalog (TIC, KIC, EPIC, K2)
+    use_resolve_all = resolve_all or is_catalog
+
+    # Send request to STScI Archive Name Translation Application (SANTA)
+    params = {'name': objectname,
+              'outputFormat': 'json',
+              'resolveAll': use_resolve_all}
+    if resolver and not use_resolve_all:
+        params['resolver'] = resolver
+    response = _simple_request('http://mastresolver.stsci.edu/Santa-war/query', params)
+    response.raise_for_status()  # Raise any errors
+    result = response.json().get('resolvedCoordinate', [])
+
+    # If a resolver is specified and resolve_all is False, find and return the result for that resolver
+    if resolver and not resolve_all:
+        resolver_result = next((res for res in result if res.get('resolver') == resolver), None)
+        if not resolver_result:
+            raise ResolverError(f'Could not resolve {objectname} to a sky position using {resolver}. '
+                                'Please try another resolver or set ``resolver=None`` to use the first '
+                                'compatible resolver.')
+        resolver_coord = SkyCoord(resolver_result['ra'], resolver_result['decl'], unit='deg')
+
+        # If object belongs to a MAST catalog, check the separation between the coordinates from the
+        # resolver and the catalog
+        if is_catalog:
+            catalog_result = next((res for res in result if res.get('resolver') == catalog), None)
+            if catalog_result:
+                catalog_coord = SkyCoord(catalog_result['ra'], catalog_result['decl'], unit='deg')
+                if resolver_coord.separation(catalog_coord) > 1 * u.arcsec:
+                    # Warn user if the coordinates differ by more than 1 arcsec
+                    warnings.warn(f'Resolver {resolver} returned coordinates that differ from MAST {catalog} catalog '
+                                  'by more than 1 arcsec. ', InputWarning)
+
+        log.debug(f'Coordinates resolved using {resolver}: {resolver_coord}')
+        return resolver_coord
+
+    if not result:
+        raise ResolverError('Could not resolve {} to a sky position.'.format(objectname))
+
+    # Return results for all compatible resolvers
+    if resolve_all:
+        return {
+            res['resolver']: SkyCoord(res['ra'], res['decl'], unit='deg')
+            for res in result
+        }
+
+    # Case when resolve_all is False and no resolver is specified
+    # SANTA returns result from first compatible resolver
+    coord = SkyCoord(result[0]['ra'], result[0]['decl'], unit='deg')
+    log.debug(f'Coordinates resolved using {result[0]["resolver"]}: {coord}')
+    return coord
+
+
+def parse_input_location(*, coordinates=None, objectname=None, resolver=None):
     """
     Convenience function to parse user input of coordinates and objectname.
 
@@ -136,6 +207,11 @@ def parse_input_location(coordinates=None, objectname=None):
         The target around which to search, by name (objectname="M104")
         or TIC ID (objectname="TIC 141914082").
         One and only one of coordinates and objectname must be supplied.
+    resolver : str, optional
+        The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+        If not specified, the default resolver order will be used. Please see the
+        `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+        for more information. Default is None.
 
     Returns
     -------
@@ -150,8 +226,11 @@ def parse_input_location(coordinates=None, objectname=None):
     if not (objectname or coordinates):
         raise InvalidQueryError("One of objectname and coordinates must be specified.")
 
+    if not objectname and resolver:
+        warnings.warn("Resolver is only used when resolving object names and will be ignored.", InputWarning)
+
     if objectname:
-        obj_coord = resolve_object(objectname)
+        obj_coord = resolve_object(objectname, resolver=resolver)
 
     if coordinates:
         obj_coord = commons.parse_coordinates(coordinates)
diff --git a/docs/mast/mast.rst b/docs/mast/mast.rst
index 6844a7f53f..9451e64a34 100644
--- a/docs/mast/mast.rst
+++ b/docs/mast/mast.rst
@@ -80,6 +80,39 @@ This token can be overwritten using the ``reenter_token`` argument.
 To logout before a session expires, the `~astroquery.mast.MastClass.logout` method may be used.
 
 
+Resolving Object Names
+=======================
+
+Each of the MAST query classes has a `~astroquery.mast.MastClass.resolve_object` method that translates named targets into
+coordinates. This method uses the `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`_
+service.
+
+The `~astroquery.mast.MastClass.resolve_object` method accepts an object name to resolve into coordinates. If the ``resolver``
+parameter is specified, then only that resolver will be queried. If the ``resolver`` parameter is not specified, then all available resolvers 
+will be queried in a default order, and the first one to return a result will be used. 
+Options for the ``resolver`` parameter are "SIMBAD" and "NED".
+
+.. doctest-remote-data::
+   
+   >>> from astroquery.mast import Mast
+   >>> mast = Mast()
+   >>> coords = mast.resolve_object("M101", resolver="NED")
+   >>> print(coords)
+   <SkyCoord (ICRS): (ra, dec) in deg
+    (210.80227, 54.34895)>
+
+If the ``resolve_all`` parameter is set to ``True``, all resolvers will be queried, and those that give a result will be returned.
+The ``resolver`` parameter is ignored in this case. The results are returned as a dictionary, with the resolver name as the key and 
+the coordinates as the value.
+
+.. doctest-remote-data::
+
+   >>> coords = mast.resolve_object("TIC 441662144", resolve_all=True)
+   >>> print(coords)
+   {'TIC': <SkyCoord (ICRS): (ra, dec) in deg
+    (210.75138371, 54.49144496)>}
+
+
 Additional Resources
 ====================
 
diff --git a/docs/mast/mast_catalog.rst b/docs/mast/mast_catalog.rst
index 8bc1110900..6acb3d24a8 100644
--- a/docs/mast/mast_catalog.rst
+++ b/docs/mast/mast_catalog.rst
@@ -29,7 +29,7 @@ If no catalog is specified, the Hubble Source Catalog will be queried.
 
    >>> from astroquery.mast import Catalogs
    ...
-   >>> catalog_data = Catalogs.query_object("158.47924 -7.30962", catalog="Galex")
+   >>> catalog_data = Catalogs.query_region("158.47924 -7.30962", catalog="Galex")
    >>> print(catalog_data[:10])  # doctest: +IGNORE_OUTPUT
     distance_arcmin          objID        survey ... fuv_flux_aper_7 fuv_artifact
    ------------------ ------------------- ------ ... --------------- ------------


Reviews:
user: login: bsipocz
body: We have a related test failure, please have a look into it:

```
>>> ned_loc = utils.resolve_object("jw100", resolver="NED")
...
E               astroquery.exceptions.ResolverError: Could not resolve jw100 to a sky position using NED. Please try another resolver or set ``resolver=None`` to use the first compatible resolver.
```


state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-23T19:54:17Z
user: login: bsipocz
body: Minor comments about mandatory kwargs. Besides those this needs a rebase to resolve the changelog conflict
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T01:15:40Z
user: login: bsipocz
body: Thanks!

(ci failure is unrelated)
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-28T15:55:44Z

Review comments:
diff_hunk: @@ -90,39 +87,115 @@ def _simple_request(url, params=None):
     return response
 
 
-def resolve_object(objectname):
+def resolve_object(objectname, resolver=None, resolve_all=False):
path: astroquery/mast/utils.py
user: login: bsipocz
body: Make these mandatory kwargs, here and the other methods, too.
created_at: 2025-04-25T01:10:10Z
author_association: MEMBER
diff_hunk: @@ -90,39 +87,115 @@ def _simple_request(url, params=None):
     return response
 
 
-def resolve_object(objectname):
+def resolve_object(objectname, resolver=None, resolve_all=False):
     """
     Resolves an object name to a position on the sky.
 
     Parameters
     ----------
     objectname : str
         Name of astronomical object to resolve.
+    resolver : str, List, optional
+        Name of resolver. Must be "NED" or "SIMBAD". This parameter is case-insensitive.
+    resolver : str, optional
+        The resolver to use when resolving a named target into coordinates. Valid options are "SIMBAD" and "NED".
+        If not specified, the default resolver order will be used. Please see the
+        `STScI Archive Name Translation Application (SANTA) <https://mastresolver.stsci.edu/Santa-war/>`__
+        for more information. If ``resolve_all`` is True, this parameter will be ignored. Default is None.
+    resolve_all : bool, optional
+        If True, will try to resolve the object name using all available resolvers ("NED", "SIMBAD").
+        Function will return a dictionary where the keys are the resolver names and the values are the
+        resolved coordinates. Default is False.
 
     Returns
     -------
-    response : `~astropy.coordinates.SkyCoord`
-        The sky position of the given object.
+    response : `~astropy.coordinates.SkyCoord`, dict
+        If ``resolve_all`` is False, returns a `~astropy.coordinates.SkyCoord` object with the resolved coordinates.
+        If ``resolve_all`` is True, returns a dictionary where the keys are the resolver names and the values are
+        `~astropy.coordinates.SkyCoord` objects with the resolved coordinates.
     """
-
-    request_args = {"service": "Mast.Name.Lookup",
-                    "params": {'input': objectname, 'format': 'json'}}
-    request_string = 'request={}'.format(parse.quote(json.dumps(request_args)))
-
-    response = _simple_request("{}/api/v0/invoke".format(conf.server), request_string)
-    result = response.json()
-
-    if len(result['resolvedCoordinate']) == 0:
-        raise ResolverError("Could not resolve {} to a sky position.".format(objectname))
-
-    ra = result['resolvedCoordinate'][0]['ra']
-    dec = result['resolvedCoordinate'][0]['decl']
-    coordinates = coord.SkyCoord(ra, dec, unit="deg")
-
-    return coordinates
-
-
-def parse_input_location(coordinates=None, objectname=None):
+    is_catalog = False  # Flag to check if object name belongs to a MAST catalog
+    catalog = None  # Variable to store the catalog name
+    objectname = objectname.strip()
+    catalog_prefixes = {
+        'TIC ': 'TIC',
+        'KIC ': 'KEPLER',
+        'EPIC ': 'K2'
+    }
+
+    if resolver:
+        # Check that resolver is valid
+        resolver = resolver.upper()
+        if resolver not in ('NED', 'SIMBAD'):
+            raise ResolverError('Invalid resolver. Must be "NED" or "SIMBAD".')
+
+        if resolve_all:
+            # Warn if user is trying to use a resolver with resolve_all
+            warnings.warn('The resolver parameter is ignored when resolve_all is True. '
+                          'Coordinates will be resolved using all available resolvers.', InputWarning)
+
+        # Check if object belongs to a MAST catalog
+        for prefix, name in catalog_prefixes.items():
+            if objectname.startswith(prefix):
+                is_catalog = True
+                catalog = name
+                break
+
+    # Whether to set resolveAll to True when making the HTTP request
+    # Should be True when resolve_all = True or when object name belongs to a MAST catalog (TIC, KIC, EPIC, K2)
+    use_resolve_all = resolve_all or is_catalog
+
+    # Send request to STScI Archive Name Translation Application (SANTA)
+    params = {'name': objectname,
+              'outputFormat': 'json',
+              'resolveAll': use_resolve_all}
+    if resolver and not use_resolve_all:
+        params['resolver'] = resolver
+    response = _simple_request('http://mastresolver.stsci.edu/Santa-war/query', params)
+    response.raise_for_status()  # Raise any errors
+    result = response.json().get('resolvedCoordinate', [])
+
+    # If a resolver is specified and resolve_all is False, find and return the result for that resolver
+    if resolver and not resolve_all:
+        resolver_result = next((res for res in result if res.get('resolver') == resolver), None)
+        if not resolver_result:
+            raise ResolverError(f'Could not resolve {objectname} to a sky position using {resolver}. '
+                                'Please try another resolver or set ``resolver=None`` to use the first '
+                                'compatible resolver.')
+        resolver_coord = SkyCoord(resolver_result['ra'], resolver_result['decl'], unit='deg')
+
+        # If object belongs to a MAST catalog, check the separation between the coordinates from the
+        # resolver and the catalog
+        if is_catalog:
+            catalog_result = next((res for res in result if res.get('resolver') == catalog), None)
+            if catalog_result:
+                catalog_coord = SkyCoord(catalog_result['ra'], catalog_result['decl'], unit='deg')
+                if resolver_coord.separation(catalog_coord) > 1 * u.arcsec:
+                    # Warn user if the coordinates differ by more than 1 arcsec
+                    warnings.warn(f'Resolver {resolver} returned coordinates that differ from MAST {catalog} catalog '
+                                  'by more than 1 arcsec. ', InputWarning)
+
+        log.debug(f'Coordinates resolved using {resolver}: {resolver_coord}')
+        return resolver_coord
+
+    if not result:
+        raise ResolverError('Could not resolve {} to a sky position.'.format(objectname))
+
+    # Return results for all compatible resolvers
+    if resolve_all:
+        return {
+            res['resolver']: SkyCoord(res['ra'], res['decl'], unit='deg')
+            for res in result
+        }
+
+    # Case when resolve_all is False and no resolver is specified
+    # SANTA returns result from first compatible resolver
+    coord = SkyCoord(result[0]['ra'], result[0]['decl'], unit='deg')
+    log.debug(f'Coordinates resolved using {result[0]["resolver"]}: {coord}')
+    return coord
+
+
+def parse_input_location(coordinates=None, objectname=None, resolver=None):
path: astroquery/mast/utils.py
user: login: bsipocz
body: make all of these mandatory kwargs, too. I know it's breaking API, but it may prevent some buggy user code in the longer run
created_at: 2025-04-25T01:12:09Z
author_association: MEMBER
diff_hunk: @@ -90,39 +87,115 @@ def _simple_request(url, params=None):
     return response
 
 
-def resolve_object(objectname):
+def resolve_object(objectname, resolver=None, resolve_all=False):
     """
     Resolves an object name to a position on the sky.
 
     Parameters
     ----------
     objectname : str
         Name of astronomical object to resolve.
+    resolver : str, List, optional
+        Name of resolver. Must be "NED" or "SIMBAD". This parameter is case-insensitive.
path: astroquery/mast/utils.py
user: login: bsipocz
body: duplicate

```suggestion
```
created_at: 2025-04-25T01:12:48Z
author_association: MEMBER
diff_hunk: @@ -110,18 +110,29 @@ def disable_cloud_dataset(self):
         """
         pass
 
-    def resolve_object(self, objectname):
+    def resolve_object(self, objectname, resolver=None, resolve_all=False):
path: astroquery/mast/core.py
user: login: bsipocz
body: ```suggestion
    def resolve_object(self, objectname, *, resolver=None, resolve_all=False):
```
created_at: 2025-04-25T01:15:09Z
author_association: MEMBER

PR comments:
user: login: codecov[bot]
created_at: 2025-04-16T02:39:27Z
body: ## [Codecov](https://app.codecov.io/gh/astropy/astroquery/pull/3292?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=astropy) Report
Attention: Patch coverage is `95.71429%` with `3 lines` in your changes missing coverage. Please review.
> Project coverage is 69.51%. Comparing base [(`4ed16e4`)](https://app.codecov.io/gh/astropy/astroquery/commit/4ed16e4557996f9ba36c04f2d5ef4c152d2f64e9?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=astropy) to head [(`08bb761`)](https://app.codecov.io/gh/astropy/astroquery/commit/08bb761fadb20c80c37d0ad9307beb31a2999685?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=astropy).
> Report is 14 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/astropy/astroquery/pull/3292?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=astropy) | Patch % | Lines |
|---|---|---|
| [astroquery/mast/utils.py](https://app.codecov.io/gh/astropy/astroquery/pull/3292?src=pr&el=tree&filepath=astroquery%2Fmast%2Futils.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=astropy#diff-YXN0cm9xdWVyeS9tYXN0L3V0aWxzLnB5) | 94.00% | [3 Missing :warning: ](https://app.codecov.io/gh/astropy/astroquery/pull/3292?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=astropy) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #3292      +/-   ##
==========================================
+ Coverage   69.36%   69.51%   +0.15%     
==========================================
  Files         232      232              
  Lines       19692    19739      +47     
==========================================
+ Hits        13659    13722      +63     
+ Misses       6033     6017      -16     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/astropy/astroquery/pull/3292?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=astropy).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=astropy).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: snbianco
created_at: 2025-04-24T01:40:35Z
body: Hmm, I can't reproduce this. I believe that changes were just deployed to our SANTA service, so you may have caught it while it was down?
author_association: CONTRIBUTOR