home-assistant/core · error · ConfigEntryError

invalid_credentials

invalid_credentials

Error message

Bucket cannot be accessed using provided combination of access key ID and secret access key.

What it means

Raised as ConfigEntryError (translation_key invalid_credentials) by the aws_s3 integration when session.create_client(...).head_bucket(Bucket=...) raises botocore ClientError — AWS rejected the access key ID / secret pair, or the key has no permission on the bucket. ConfigEntryError marks the entry as errored (no automatic retry) and surfaces a translated message to the user.

Source

Thrown at homeassistant/components/aws_s3/__init__.py:43

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass: HomeAssistant, entry: S3ConfigEntry) -> bool:
    """Set up S3 from a config entry."""

    data = cast(dict, entry.data)
    try:
        session = AioSession()
        # pylint: disable-next=unnecessary-dunder-call
        client = await session.create_client(
            "s3",
            endpoint_url=data.get(CONF_ENDPOINT_URL),
            aws_secret_access_key=data[CONF_SECRET_ACCESS_KEY],
            aws_access_key_id=data[CONF_ACCESS_KEY_ID],
        ).__aenter__()
        await client.head_bucket(Bucket=data[CONF_BUCKET])
    except ClientError as err:
        raise ConfigEntryError(
            translation_domain=DOMAIN,
            translation_key="invalid_credentials",
        ) from err
    except ParamValidationError as err:
        if "Invalid bucket name" in str(err):
            raise ConfigEntryError(
                translation_domain=DOMAIN,
                translation_key="invalid_bucket_name",
            ) from err
    except ValueError as err:
        raise ConfigEntryError(
            translation_domain=DOMAIN,
            translation_key="invalid_endpoint_url",
        ) from err
    except ConnectionError as err:
        raise ConfigEntryNotReady(
            translation_domain=DOMAIN,
            translation_key="cannot_connect",

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Re-enter the access key ID and secret in the aws_s3 config entry (reconfigure/re-auth flow) and verify they are exact, with no trailing whitespace.
  2. Test the same keys with aws s3api head-bucket --bucket <name> — if that also fails, fix IAM.
  3. Grant the IAM principal s3:ListBucket (and s3:GetBucketLocation) on the bucket in its policy.
  4. If the key belongs to another account, add a bucket policy allowing it, or use keys from the bucket-owning account.
Defensive patterns

Strategy: validation

Validate before calling

import re

def keys_well_formed(access_key_id: str, secret: str) -> bool:
    return bool(re.fullmatch(r"[A-Z0-9]{16,128}", access_key_id or "")) and len(secret or "") >= 16

Try / catch

from botocore.exceptions import ClientError

try:
    await client.head_bucket(Bucket=bucket)
except ClientError as err:
    code = err.response["Error"]["Code"]
    if code in ("InvalidAccessKeyId", "SignatureDoesNotMatch", "AccessDenied"):
        # credentials/permission problem — do not retry
        raise

Prevention

When it happens

Trigger: head_bucket with the configured access key ID and secret returns 403 InvalidAccessKeyId / SignatureDoesNotMatch / AccessDenied: wrong keys, deleted IAM user, or an IAM policy lacking s3:ListBucket/GetBucketLocation on the target bucket.

Common situations: Typo pasting keys; rotated/deleted access keys; IAM policy missing s3:HeadBucket permission; keys from a different AWS account than the bucket owner.

Related errors


AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14). Data as JSON: /api/errors/07f06bcfe4d0609a. Report an issue: GitHub.