boto/boto3 · error · NotImplementedError

Search path hits shape type

Error message

Search path hits shape type {shape.type_name} from {item}

What it means

Raised while constructing an empty placeholder response from a service model shape. The code walks the response `search_path` segment by segment and only knows how to descend into `structure` (via `.members`) and `list` (via `.member`) shapes. If a path segment lands on a `map`, scalar, or other shape type, the traversal cannot continue and NotImplementedError is raised. Like error 20, this is an internal model/shape mismatch rather than a user input problem.

Solutions

  1. Upgrade boto3 and botocore together to the latest release so service models and resource models agree.
  2. If a specific API version is requested for the resource, drop the `api_version=` argument so boto3 picks the default, model-consistent version.
  3. Reinstall boto3 cleanly (`pip install --force-reinstall boto3`) to rule out a corrupt data file.
  4. Report the failing service + path to boto3 maintainers if it reproduces on a clean install of the latest version.

Example fix

# before: pinning an old api_version that diverges from current shapes
import boto3
sess = boto3.Session()
sess.resource('s3', api_version='2006-03-01')  # path may hit a changed shape

# after: omit api_version to let boto3 resolve a consistent pair
sess.resource('s3')
Defensive patterns

Strategy: type-guard

Validate before calling

import boto3
# Validate api_version against available versions before use
svc = 's3'
loader = boto3.session.Session()._loader
versions = loader.list_api_versions(svc, 'resources-1')
# then call resource without forcing an unsupported api_version

Type guard

def supported_resource_api(session, service, requested=None):
    versions = session._loader.list_api_versions(service, 'resources-1')
    if requested and requested not in versions:
        return None  # let boto3 pick default
    return requested or versions[-1]

Try / catch

try:
    res = sess.resource('s3')
except NotImplementedError:
    res = sess.resource('s3')  # drop api_version and retry; or upgrade

Prevention

When it happens

Trigger: A resource model's `path` (e.g. `foo.bar[0].baz`) for a load/action references a member whose resolved shape is a `map` or a scalar, so `build_empty_response` cannot step into it. Surfaced when an operation returns an empty payload that boto3 must fill in from the model.

Common situations: A service API changed a member's shape type (e.g. structure→map) in a newer API version while the bundled boto3 resource model still references the old path; running boto3 with a botocore whose service definitions disagree with the resource models; corrupted install.

Related errors


AI-assisted analysis of boto/boto3@6e10b029c1 (2026-08-11). Data as JSON: /api/errors/181034051a9d1387. Report an issue: GitHub.

Appendix: source

Thrown at boto3/resources/response.py:112

    response = None

    operation_model = service_model.operation_model(operation_name)
    shape = operation_model.output_shape

    if search_path:
        # Walk the search path and find the final shape. For example, given
        # a path of ``foo.bar[0].baz``, we first find the shape for ``foo``,
        # then the shape for ``bar`` (ignoring the indexing), and finally
        # the shape for ``baz``.
        for item in search_path.split('.'):
            item = item.strip('[0123456789]$')

            if shape.type_name == 'structure':
                shape = shape.members[item]
            elif shape.type_name == 'list':
                shape = shape.member
            else:
                raise NotImplementedError(
                    f'Search path hits shape type {shape.type_name} from {item}'
                )

    # Anything not handled here is set to None
    if shape.type_name == 'structure':
        response = {}
    elif shape.type_name == 'list':
        response = []
    elif shape.type_name == 'map':
        response = {}

    return response


class RawHandler:
    """
    A raw action response handler. This passed through the response
    dictionary, optionally after performing a JMESPath search if one

View on GitHub (pinned to 6e10b029c1)