---
url: https://aelmanaa.github.io/hardhat-kms/user/reference/errors.md
description: >-
  Every error hardhat-kms and its provider packages can raise, with its stable
  id, what it means and how to fix it, searchable by message.
---

# Errors

Audience: anyone who got an error from hardhat-kms or one of its provider packages.

Every error that hardhat-kms and its provider packages can raise has an entry here, with a stable id. The page is generated from their source, so it matches this version. Find an error by searching for a fixed part of its message.

* `{name}` in a message stands for a value, such as an address or a file name.
* Most errors start with the provider, the operation and the key, for example `aws, sign, key aws:alias/deployer: the provider call failed (AccessDeniedException)`. The tables list the part after that prefix.
* Kind `config`: a config validation message. Hardhat shows it in its `Invalid config` error, after the config path, for example `* Config error in config.kms.keys.deployer.address: …`.
* Kind `reason`: text that another error includes, such as the reason in `the provider returned an invalid signature ({reason})`.
* Kind `internal`: a plain `Error` that only a bug or a broken install can cause.

Errors never include credentials or the text of an SDK error, which can carry request details. Run with `DEBUG=hardhat:kms:*` to see each step; see [Debug output](https://aelmanaa.github.io/hardhat-kms/user/guides/debug-output.md).

## hardhat-kms

### Configuration

| Id                                        | Kind   | Message                                                                                                                                                    | Cause                                                                                                                                                                                                                                                                                                    | Fix                                                                                                                                      |
| ----------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `core.config.timeout-type`                | config | `Expected a number of milliseconds`                                                                                                                        | `timeoutMs`, on a key or in `kms.defaults`, is not a number.                                                                                                                                                                                                                                             | Set it to a number of milliseconds, such as `30_000`.                                                                                    |
| `core.config.timeout-integer`             | config | `Expected an integer number of milliseconds`                                                                                                               | `timeoutMs`, on a key or in `kms.defaults`, has a fraction.                                                                                                                                                                                                                                              | Use a whole number of milliseconds.                                                                                                      |
| `core.config.timeout-min`                 | config | `Expected at least 1 ms`                                                                                                                                   | `timeoutMs`, on a key or in `kms.defaults`, is 0 or negative.                                                                                                                                                                                                                                            | Use a positive number of milliseconds. The default `timeoutMs` is 30000.                                                                 |
| `core.config.timeout-max`                 | config | `Expected at most 2147483647 ms`                                                                                                                           | `timeoutMs`, on a key or in `kms.defaults`, is larger than Node.js timers accept (2^31 - 1 ms, about 24.8 days).                                                                                                                                                                                         | Use a smaller value.                                                                                                                     |
| `core.config.address`                     | config | `Expected a 0x-prefixed 20-byte address, all lowercase, all uppercase or with a valid EIP-55 checksum`                                                     | A key's `address` pin is not an address, or it is mixed-case and its EIP-55 checksum is wrong, which usually means a typo.                                                                                                                                                                               | Copy the address from `npx hardhat kms address <key>`, or write it in lowercase.                                                         |
| `core.config.non-empty`                   | config | `Expected a non-empty string`                                                                                                                              | A string field of the `kms` config, such as `provider`, `region` or `profile`, is empty.                                                                                                                                                                                                                 | Set the field, or remove it if it is optional.                                                                                           |
| `core.config.whitespace`                  | config | `Unexpected leading or trailing whitespace`                                                                                                                | A string field of the `kms` config starts or ends with whitespace.                                                                                                                                                                                                                                       | Remove the spaces, tabs or newlines around the value.                                                                                    |
| `core.config.setting-type`                | config | `Expected a string or a Configuration Variable`                                                                                                            | An AWS key's `region` or `profile`, or `kms.defaults.aws.region`, is neither a string nor `configVariable(...)`.                                                                                                                                                                                         | Use a string, such as `us-east-1` for a region, or `configVariable(...)`.                                                                |
| `core.config.provider-misspelled`         | config | `Unknown provider "{provider}". Did you mean "{suggestion}"?`                                                                                              | A key's `provider` matches a built-in provider id (`aws`, `gcp`, `azure`) in another case, or is one edit away from one, such as `AWS` or `gpc`.                                                                                                                                                         | Use the id the message suggests. A third-party provider needs an id that does not look like a built-in one.                              |
| `core.config.provider-reserved`           | config | `Provider "{provider}" is reserved for the planned {name} provider, which is not released yet (https://github.com/aelmanaa/hardhat-kms/issues/{issue})`    | A key's `provider` is `turnkey` or `fireblocks`, in any case. hardhat-kms keeps these ids for its planned Turnkey and Fireblocks providers, so no other plugin can use them.                                                                                                                             | Follow the linked issue for the release, or use another provider. A third-party provider needs an id of its own.                         |
| `core.config.key-shape`                   | config | ``Expected a key object with a `provider` field, for example { provider: "aws", keyId: "alias/deployer" }``                                                | An entry of `kms.keys`, or a key object in `kmsAccounts`, is not an object with a string `provider`.                                                                                                                                                                                                     | Write the key as an object with a `provider` field and the fields of that provider.                                                      |
| `core.config.account-shape`               | config | ``Expected the name of a key in `kms.keys` or a key object``                                                                                               | An entry of a network's `kmsAccounts` is neither a string nor an object.                                                                                                                                                                                                                                 | List key names from `kms.keys`, or key objects.                                                                                          |
| `core.config.key-name`                    | config | `` Key names start with a letter and use at most 64 letters, digits, `_` or `-` ``                                                                         | A name in `kms.keys` has another character, starts with a digit or is too long.                                                                                                                                                                                                                          | Rename the key. Tasks take key names on the command line, so they are kept simple.                                                       |
| `core.config.simulated-balance-type`      | config | `Expected a bigint amount of wei, for example 10n ** 18n`                                                                                                  | `kms.simulatedBalance` is not a bigint, for example a number or a string.                                                                                                                                                                                                                                | Write it as a bigint, such as `10n ** 18n` for 1 ETH.                                                                                    |
| `core.config.simulated-balance-negative`  | config | `Expected a non-negative amount of wei`                                                                                                                    | `kms.simulatedBalance` is negative.                                                                                                                                                                                                                                                                      | Use 0 or more wei.                                                                                                                       |
| `core.config.unknown-key-empty`           | config | ``Unknown key "{account}". `kms.keys` is empty.``                                                                                                          | A network's `kmsAccounts` names a key, but `kms.keys` defines none.                                                                                                                                                                                                                                      | Define the key in `kms.keys`, or put the key object in `kmsAccounts` instead of its name.                                                |
| `core.config.unknown-key`                 | config | `Unknown key "{account}". Known keys: {known}.`                                                                                                            | A network's `kmsAccounts` names a key that `kms.keys` does not define. Names are case-sensitive.                                                                                                                                                                                                         | Use one of the names listed, or add the key to `kms.keys`.                                                                               |
| `core.config.key-listed-twice`            | config | `Key "{account}" is listed twice`                                                                                                                          | A network's `kmsAccounts` names the same key twice.                                                                                                                                                                                                                                                      | Remove the repeated name.                                                                                                                |
| `core.config.aws-endpoint`                | config | `Expected an http or https URL without credentials, such as http://localhost:4566`                                                                         | An AWS key's `endpoint` is not an http or https URL, or it has a user name or password, which would end up in logs and errors.                                                                                                                                                                           | Use a plain URL. The AWS SDK takes credentials from its own chain, never from the URL.                                                   |
| `core.config.aws-key-id`                  | config | ``Expected a key id, a key ARN, an alias name (`alias/...`) or an alias ARN``                                                                              | An AWS key's `keyId` has none of the forms AWS KMS accepts.                                                                                                                                                                                                                                              | Use the key id, the key ARN, `alias/<name>` or the alias ARN, as `aws kms list-aliases` shows them.                                      |
| `core.config.aws-region-conflict`         | config | `Conflicts with the region in the key ARN ({region})`                                                                                                      | An AWS key's `keyId` is an ARN, and its `region` names another region than the ARN.                                                                                                                                                                                                                      | Remove `region`: an ARN already names the region.                                                                                        |
| `core.config.azure-either-form`           | config | ``Use either `keyId` or `vaultUrl` with `keyName` (and an optional `keyVersion`), not both``                                                               | An Azure key mixes the `keyId` form and the `vaultUrl` form.                                                                                                                                                                                                                                             | Keep one form: `keyId` alone, or `vaultUrl` with `keyName` and an optional `keyVersion`.                                                 |
| `core.config.azure-key-id`                | config | ``Expected an https URL on an Azure Key Vault or Managed HSM host (for example `*.vault.azure.net`) with the path /keys/<name> or /keys/<name>/<version>`` | An Azure key's `keyId` is not a Key Vault or Managed HSM key URL.                                                                                                                                                                                                                                        | Copy the key identifier from `az keyvault key show` (its `key.kid`), or from the portal.                                                 |
| `core.config.azure-vault-url`             | config | ``Expected an https URL on an Azure Key Vault or Managed HSM host (for example `*.vault.azure.net`), with no path``                                        | An Azure key's `vaultUrl` is not the https URL of a vault or Managed HSM, or it has a path.                                                                                                                                                                                                              | Use the vault URL alone, such as `https://my-vault.vault.azure.net`, and put the key in `keyName`.                                       |
| `core.config.azure-key-name`              | config | `Expected 1 to 127 letters, digits or dashes`                                                                                                              | An Azure key's `keyName` has a character Key Vault does not allow in key names, or is too long.                                                                                                                                                                                                          | Use the key's name as Key Vault shows it.                                                                                                |
| `core.config.azure-key-version`           | config | `Expected letters and digits only`                                                                                                                         | An Azure key's `keyVersion` is not a Key Vault version id.                                                                                                                                                                                                                                               | Copy the version from `az keyvault key list-versions`, or remove `keyVersion` to use the current version.                                |
| `core.config.azure-workspace-id`          | config | `Expected a Log Analytics workspace id, a GUID such as 00000000-0000-0000-0000-000000000000`                                                               | `kms.audit.azure.workspaceId` is not a GUID. It takes the workspace id, not the workspace name or resource id.                                                                                                                                                                                           | Copy the workspace id from `az monitor log-analytics workspace show --query customerId`, or from the workspace's overview in the portal. |
| `core.config.gcp-either-form`             | config | ``Use either `keyVersionName` or `projectId`, `location`, `keyRing`, `keyName` and `keyVersion`, not both``                                                | A Google Cloud key mixes the `keyVersionName` form and the parts form.                                                                                                                                                                                                                                   | Keep one form: `keyVersionName` alone, or all five parts.                                                                                |
| `core.config.gcp-key-version-name`        | config | `Expected projects/<project>/locations/<location>/keyRings/<ring>/cryptoKeys/<key>/cryptoKeyVersions/<version>`                                            | A Google Cloud key's `keyVersionName` is not the resource name of a key version.                                                                                                                                                                                                                         | Copy the name from `gcloud kms keys versions list`; it ends with `/cryptoKeyVersions/<version>`.                                         |
| `core.config.gcp-key-version-type`        | config | `Expected a positive integer, a string or a Configuration Variable`                                                                                        | A Google Cloud key's `keyVersion` is another type, or a number that is not a positive integer.                                                                                                                                                                                                           | Use the version number, such as `1`, a string, or `configVariable(...)`.                                                                 |
| `core.config.gcp-segment`                 | config | `` Expected letters, digits, `_`, `.`, `:` or `-`, and not `.` or `..` ``                                                                                  | A Google Cloud key's `projectId`, `location`, `keyRing` or `keyName` has a character a resource name cannot hold.                                                                                                                                                                                        | Check the value for a typo, against the key's resource name in `gcloud kms keys versions list`.                                          |
| `core.config.gcp-key-version`             | config | `Expected a positive integer version`                                                                                                                      | A Google Cloud key's `keyVersion` string is not a positive integer.                                                                                                                                                                                                                                      | Use the version number, such as `"1"`.                                                                                                   |
| `core.config.invalid-value`               | error  | `invalid value for {path} ({display}): {problem}`                                                                                                          | A key identifier does not have its provider's format. A value from a configuration variable is checked when it is read, which config validation cannot do. `{path}` is the config path, such as `kms.keys.deployer.keyId` or `--kms aws`, and `{display}` shows a variable by its name, never its value. | Fix the value, or the variable it comes from. The part after the colon is one of the reasons below.                                      |
| `core.config.aws-key-id-reason`           | reason | ``expected a key id, a key ARN, an alias name (`alias/...`) or an alias ARN``                                                                              | An AWS `keyId` has none of the forms AWS KMS accepts.                                                                                                                                                                                                                                                    | Use the key id, the key ARN, `alias/<name>` or the alias ARN.                                                                            |
| `core.config.aws-region-conflict-reason`  | reason | ``the key ARN's region conflicts with `region` ({region})``                                                                                                | An AWS `keyId` is an ARN in another region than the key's `region`. `{region}` shows a region from a configuration variable by the variable's name, never its value.                                                                                                                                     | Remove `region`, or fix the ARN.                                                                                                         |
| `core.config.azure-key-id-reason`         | reason | ``expected an https URL on an Azure Key Vault or Managed HSM host (for example `*.vault.azure.net`) with the path /keys/<name> or /keys/<name>/<version>`` | An Azure `keyId`, or the URL built from `vaultUrl`, `keyName` and `keyVersion`, is not a key URL.                                                                                                                                                                                                        | Copy the key identifier from `az keyvault key show`, or fix the parts.                                                                   |
| `core.config.azure-workspace-id-reason`   | reason | `expected a Log Analytics workspace id, a GUID`                                                                                                            | The configuration variable of `kms.audit.azure.workspaceId` holds something other than a GUID.                                                                                                                                                                                                           | Set the variable to the workspace id from `az monitor log-analytics workspace show --query customerId`.                                  |
| `core.config.gcp-key-version-name-reason` | reason | `expected projects/<project>/locations/<location>/keyRings/<ring>/cryptoKeys/<key>/cryptoKeyVersions/<version>`                                            | A Google Cloud `keyVersionName`, or the name built from its parts, is not a key version name.                                                                                                                                                                                                            | Copy the name from `gcloud kms keys versions list`.                                                                                      |
| `core.config.gcp-segment-reason`          | reason | `` expected letters, digits, `_`, `.`, `:` or `-`, and not `.` or `..` ``                                                                                  | A Google Cloud `projectId`, `location`, `keyRing` or `keyName` has a character a resource name cannot hold.                                                                                                                                                                                              | Check the value for a typo, against the key's resource name in `gcloud kms keys versions list`.                                          |
| `core.config.gcp-key-version-reason`      | reason | `expected a positive integer version`                                                                                                                      | A Google Cloud `keyVersion` is not a positive integer.                                                                                                                                                                                                                                                   | Use the version number, such as `1`.                                                                                                     |

### The `--kms` option

| Id                                           | Kind  | Message                                                                                       | Cause                                                                                                                                       | Fix                                                                                               |
| -------------------------------------------- | ----- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `core.kms-option.empty`                      | error | `--kms: expected one or more of aws, gcp and azure, such as --kms aws`                        | `--kms` was given an empty value.                                                                                                           | Name the providers whose environment variables hold keys, such as `--kms aws` or `--kms aws,gcp`. |
| `core.kms-option.unknown-provider-suggested` | error | `--kms {provider}: unknown provider. Did you mean "{suggestion}"? Expected aws, gcp or azure` | `--kms` names a provider that is close to a built-in one, such as `AWS` or `gpc`.                                                           | Use the suggested id. `--kms` reads only the built-in providers' variables.                       |
| `core.kms-option.unknown-provider`           | error | `--kms {provider}: unknown provider. Expected aws, gcp or azure`                              | `--kms` names a provider other than `aws`, `gcp` and `azure`. Third-party providers are configured in `kms.keys` only.                      | Use `aws`, `gcp` or `azure`, or configure the key in the Hardhat config.                          |
| `core.kms-option.listed-twice`               | error | `--kms {provider}: listed twice`                                                              | `--kms` names the same provider twice.                                                                                                      | Name each provider once.                                                                          |
| `core.kms-option.list-empty`                 | error | `--kms {provider}: {list} holds no key ids`                                                   | `AWS_KMS_KEY_IDS` or `AZURE_KEY_VAULT_KEY_IDS` is set, but holds only commas and spaces.                                                    | Put comma-separated key ids in it, or unset it to use the single-key variable.                    |
| `core.kms-option.not-set`                    | error | `--kms {provider}: set {single}, or {list} for several keys`                                  | `--kms aws` or `--kms azure` was given, but neither of the provider's key variables is set.                                                 | Export the variable the message names, such as `AWS_KMS_KEY_ID=alias/deployer`.                   |
| `core.kms-option.repeated`                   | error | `--kms {provider}: {name} repeats {first}`                                                    | A list variable such as `AWS_KMS_KEY_IDS` holds the same key id twice.                                                                      | Remove the repeated entry.                                                                        |
| `core.kms-option.variable-not-set`           | error | `--kms {provider}: {name} is not set`                                                         | `--kms gcp` needs all of `GCP_PROJECT_ID`, `GCP_LOCATION`, `GCP_KEY_RING`, `GCP_KEY_NAME` and `GCP_KEY_VERSION`, and one is unset or empty. | Export the variable the message names.                                                            |

### Provider plugins

| Id                                         | Kind  | Message                                                                                                                                                                                                    | Cause                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Fix                                                                                                                                    |
| ------------------------------------------ | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `core.provider.adapter-nothing`            | error | ``a kms.createKeyAdapter handler returned nothing for this key. Handlers must return `await next(context, key)` for keys of other providers``                                                              | A provider plugin's `createKeyAdapter` handler returned `undefined` or `null` instead of passing the key on.                                                                                                                                                                                                                                                                                                                                                           | If you wrote the handler, return `await next(context, key)` for keys it does not handle. Otherwise report it to the provider plugin.   |
| `core.provider.adapter-not-object`         | error | `the adapter for this key is not an object`                                                                                                                                                                | A provider plugin's `createKeyAdapter` handler returned a value that is not an adapter object.                                                                                                                                                                                                                                                                                                                                                                         | Report it to the provider plugin; see the adapter contract in the provider guide.                                                      |
| `core.provider.adapter-no-describe`        | error | `the adapter for this key has no describe() method`                                                                                                                                                        | The adapter a provider plugin returned has no `describe()` method, which every adapter needs.                                                                                                                                                                                                                                                                                                                                                                          | Report it to the provider plugin.                                                                                                      |
| `core.provider.adapter-not-function`       | error | `the adapter's {method} is not a function`                                                                                                                                                                 | The adapter has a property with a method's name, but it is not a function.                                                                                                                                                                                                                                                                                                                                                                                             | Report it to the provider plugin.                                                                                                      |
| `core.provider.adapter-no-signing`         | error | `the adapter for this key has no signing method ({methods})`                                                                                                                                               | The adapter implements none of `signDigest`, `signMessage` and `signTypedData`.                                                                                                                                                                                                                                                                                                                                                                                        | Report it to the provider plugin.                                                                                                      |
| `core.provider.adapter-no-identity`        | error | ``the adapter for this key can neither return a public key nor an address, and the key has no `address` pin``                                                                                              | The adapter has neither `getPublicKey` nor `getAddress`, so only a pin can tell which address it signs for.                                                                                                                                                                                                                                                                                                                                                            | Set `address` on the key to the account's address. The first signature checks it.                                                      |
| `core.provider.adapter-describe-failed`    | error | `the adapter's describe() failed ({errorName})`                                                                                                                                                            | The adapter's `describe()` threw. Only the error's class name is shown.                                                                                                                                                                                                                                                                                                                                                                                                | Report it to the provider plugin.                                                                                                      |
| `core.provider.adapter-describe-fields`    | error | `the adapter's describe() must return non-empty strings for {fields}`                                                                                                                                      | The adapter's `describe()` result lacks `provider`, `pinnedId` or `displayId`, or one is empty.                                                                                                                                                                                                                                                                                                                                                                        | Report it to the provider plugin.                                                                                                      |
| `core.provider.no-plugin`                  | error | ``no plugin provides "{provider}" keys. Add the plugin for this provider to `plugins` in your Hardhat config, or check the `provider` field``                                                              | No plugin in the Hardhat config handles keys of this `provider`.                                                                                                                                                                                                                                                                                                                                                                                                       | Add the provider's plugin to `plugins`, or fix the key's `provider` field.                                                             |
| `core.provider.not-available`              | error | `signing with {name} keys is not available yet (https://github.com/aelmanaa/hardhat-kms/issues/{issue})`                                                                                                   | The provider is planned, but its adapter is not released yet. A key with a reserved id such as `turnkey` gets this error too when it reaches the resolved config without validation, for example through another plugin's config hook.                                                                                                                                                                                                                                 | Follow the linked issue, or use another provider.                                                                                      |
| `core.provider.package-missing`            | error | ``{name} keys need the {package} plugin. Install it with `npm install --save-dev {package}` and add it to `plugins` in your Hardhat config``                                                               | The config has a key of a built-in provider, but the provider's package is not in `plugins`.                                                                                                                                                                                                                                                                                                                                                                           | Install the package the message names and add its plugin to `plugins`.                                                                 |
| `core.provider.adapter-failed`             | error | `creating the adapter failed ({errorName})`                                                                                                                                                                | A provider plugin threw while building the key's adapter, for example when its cloud SDK failed to load. Only the error's class name is shown, since SDK messages can carry request details.                                                                                                                                                                                                                                                                           | Check that the provider's SDK is installed (`npm ls`), and run with `DEBUG=hardhat:kms:*` to see the step that failed.                 |
| `core.provider.version-mismatch`           | error | `` {package} {version} needs hardhat-kms {version}, but hardhat-kms {core} is installed. Install the same version of both, for example `npm install --save-dev hardhat-kms@{target} {package}@{target}` `` | A first-party provider package and hardhat-kms have different versions. They are released together, and the provider package asks for its own version of hardhat-kms as a peer dependency. Measured on new projects that install both packages: npm 11.15.0 stops the install with `ERESOLVE` unless it runs with `--legacy-peer-deps`; pnpm 12.8.1, Yarn 1.22.22 and Yarn 4.18.1 warn and install both. The check runs the first time a key of that provider is used. | Run the install command the message prints.                                                                                            |
| `core.provider.version-mismatch-no-target` | error | `{package} {version} needs hardhat-kms {version}, but hardhat-kms {core} is installed. Install the same version of both`                                                                                   | As above, with a version that is not a plain `major.minor.patch`, such as a tag, so no install command is suggested.                                                                                                                                                                                                                                                                                                                                                   | Install the same version of hardhat-kms and the provider package.                                                                      |
| `core.provider.debug-namespace-invalid`    | error | `kmsDebug namespace {namespace} is not valid: use 1 to 64 lowercase letters, digits and -, starting with a letter`                                                                                         | A provider package called `kmsDebug` from `hardhat-kms/provider-utils` with a namespace that is empty, longer than 64 characters, does not start with a letter, or holds another character, such as an uppercase letter, `*`, `,` or `:`. `*`, `,` and `:` would change which `DEBUG` patterns match it.                                                                                                                                                               | If you wrote the provider package, pass its provider id to `kmsDebug`, such as `myvault`. Otherwise report it to the provider package. |
| `core.provider.debug-namespace-reserved`   | error | `kmsDebug namespace {namespace} belongs to hardhat-kms ({reserved}); log under the provider id instead`                                                                                                    | A provider package called `kmsDebug` from `hardhat-kms/provider-utils` with one of the namespaces hardhat-kms logs under, so its lines would pass for the core's.                                                                                                                                                                                                                                                                                                      | If you wrote the provider package, pass its provider id to `kmsDebug`, such as `myvault`. Otherwise report it to the provider package. |

### Signing

| Id                                 | Kind   | Message                                                                                                                                                                                                                                                                                                                                                        | Cause                                                                                                                                                                                                                                                                                                                        | Fix                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ---------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `core.signer.no-identity`          | error  | ``the adapter can neither return a public key nor an address; set an `address` pin``                                                                                                                                                                                                                                                                           | The key's adapter has neither `getPublicKey` nor `getAddress`, and the key has no `address`.                                                                                                                                                                                                                                 | Set `address` on the key to the account's address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `core.signer.timeout-range`        | error  | `the timeout must be an integer from 1 to 2147483647 ms, got {timeout}`                                                                                                                                                                                                                                                                                        | A signer was created with a `timeoutMs` that Node.js cannot schedule. The config validation refuses such values first.                                                                                                                                                                                                       | Set `timeoutMs` to an integer from 1 to 2147483647.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `core.signer.address-invalid`      | error  | `the configured address is invalid: {reason}`                                                                                                                                                                                                                                                                                                                  | The key's `address` pin is not a valid address. The config validation refuses such values first.                                                                                                                                                                                                                             | Copy the address from `npx hardhat kms address <key>`, or write it in lowercase.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `core.signer.address-only`         | error  | `the provider returns only the key's address, not its public key`                                                                                                                                                                                                                                                                                              | The provider's adapter reports an address but no public key, and the key has not signed yet in this run, which would reveal it.                                                                                                                                                                                              | Use a provider that returns the public key. An address-only provider reveals it only once the key has signed in the same run.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `core.signer.eip191-failed`        | error  | `the signature failed EIP-191 verification`                                                                                                                                                                                                                                                                                                                    | The final check of a personal-message signature failed, after the signature had passed the low-level checks. The signature is not released.                                                                                                                                                                                  | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `core.signer.eip712-failed`        | error  | `the signature failed EIP-712 verification`                                                                                                                                                                                                                                                                                                                    | The final check of a typed-data signature failed, after the signature had passed the low-level checks. The signature is not released.                                                                                                                                                                                        | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `core.signer.cannot-identify`      | error  | `the adapter cannot identify its key`                                                                                                                                                                                                                                                                                                                          | The key's adapter has neither `getPublicKey` nor `getAddress`, and the key has no `address`. Creating the adapter refuses such a key first, so this is a guard.                                                                                                                                                              | Set `address` on the key to the account's address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `core.signer.address-mismatch`     | error  | `the key derives to {address}, but the configured address is {expected}, so nothing was signed. The key id may now name the wrong key or a substituted one, or the pin may be wrong. Do not change the pin to match until you know why the key changed; see "When the pin fails" in the key rotation guide, which also covers a deliberate move to a new key.` | The key's public key gives another address than its `address` pin: the key id, alias or version now names another key, by mistake or by substitution, or the pin is wrong. Nothing was signed.                                                                                                                               | Find out why the key changed before you touch the pin. If the change was a mistake, point the config back at the old key. If it was deliberate, point the old entry back at the old key and follow "Move to a new key" in the key rotation guide, which gives the new key its own entry and pin. If the pin itself is wrong, for example mistyped, do not change it until you have confirmed that the key id names the key that holds your funds and roles. Then set the pin to the address after "the key derives to" in this error, or remove the pin, run `npx hardhat kms address <key>` and pin what it prints. |
| `core.signer.digest-length`        | error  | `expected a {expected}-byte digest, got {length} bytes`                                                                                                                                                                                                                                                                                                        | Code that uses the signer asked it to sign a digest that is not 32 bytes. Nothing was sent to the provider.                                                                                                                                                                                                                  | Sign a 32-byte hash, such as a keccak256 digest.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `core.signer.invalid-signature`    | error  | `the provider returned an invalid signature ({reason})`                                                                                                                                                                                                                                                                                                        | The provider returned a signature that failed the checks twice in a row. The reason is one of the signature reasons below. A key other than the configured one fails here too.                                                                                                                                               | Check that the config names the key you expect, then run again. If it repeats, run with `DEBUG=hardhat:kms:*` and report it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `core.signer.cannot-sign`          | error  | `the provider cannot sign a {kind}`                                                                                                                                                                                                                                                                                                                            | The key's adapter has no `signDigest`, and no method for this kind of payload (`signMessage` or `signTypedData`).                                                                                                                                                                                                            | Sign another kind of payload with this key, or use a provider that signs digests.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `core.signer.key-material`         | error  | `{reason}`                                                                                                                                                                                                                                                                                                                                                     | The provider returned a public key or an address that the plugin refuses. The message is one of the reasons under Public keys and addresses.                                                                                                                                                                                 | Check that the key is a secp256k1 signing key, as the provider's setup guide creates it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `core.signer.no-answer`            | error  | `no answer within {timeout} ms`                                                                                                                                                                                                                                                                                                                                | The provider did not answer within the key's `timeoutMs`. The request may still complete at the provider; see the security model.                                                                                                                                                                                            | Check the network and the region or endpoint, or raise `timeoutMs` on the key or in `kms.defaults`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `core.signer.cancelled`            | error  | `cancelled by the caller's abort signal`                                                                                                                                                                                                                                                                                                                       | The `signal` given to `connection.kms.getAccount` aborted before or during a KMS call, so the plugin stopped waiting and returned nothing. It does not retry a cancelled call. A request that already reached the provider can still be signed there and show in its audit log, but the plugin never returns that signature. | Nothing, if the abort was meant. To sign again, get a new account with a signal that has not aborted.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `core.signer.provider-call-failed` | error  | `the provider call failed ({errorName})`                                                                                                                                                                                                                                                                                                                       | The provider's SDK threw an error that the provider plugin does not explain. Only the error's class name is shown, since SDK messages can carry request details.                                                                                                                                                             | Look the class name up in the provider's setup guide, and run with `DEBUG=hardhat:kms:*` to see the call.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `core.signer.timed-out`            | reason | `timed out after {timeout} ms`                                                                                                                                                                                                                                                                                                                                 | A provider call ran out of time. It is reported as `no answer within … ms`.                                                                                                                                                                                                                                                  | See `core.signer.no-answer`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `core.signer.cancelled-reason`     | reason | `cancelled by the caller`                                                                                                                                                                                                                                                                                                                                      | The caller's abort signal stopped a provider call. It is reported as `cancelled by the caller's abort signal`.                                                                                                                                                                                                               | See `core.signer.cancelled`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |

### Public keys and addresses

| Id                            | Kind   | Message                                                                                 | Cause                                                                                                      | Fix                                                                                               |
| ----------------------------- | ------ | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `core.key.spki-der`           | reason | `expected the canonical DER encoding of an uncompressed secp256k1 SubjectPublicKeyInfo` | The provider returned a DER public key that is not an uncompressed secp256k1 key, for example a P-256 key. | Use a secp256k1 key, as the provider's setup guide creates it.                                    |
| `core.key.jwk-key-type`       | reason | `expected an EC key, got key type "{keyType}"`                                          | The provider returned a JSON Web Key that is not an elliptic-curve key, for example an RSA key.            | Use an EC key on the secp256k1 curve.                                                             |
| `core.key.jwk-curve`          | reason | `expected curve P-256K (secp256k1), got "{curve}"`                                      | The provider returned an EC JSON Web Key on another curve, such as P-256.                                  | Use a key on the secp256k1 curve (P-256K).                                                        |
| `core.key.length`             | reason | `expected a 65-byte uncompressed public key`                                            | A public key does not have the 65 bytes of an uncompressed secp256k1 point (`0x04`, x, y).                 | If a provider plugin returned it, report it to the plugin.                                        |
| `core.key.not-on-curve`       | reason | `the public key is not a point on secp256k1`                                            | The public key's coordinates are not a point on the secp256k1 curve: it is corrupt, or from another curve. | Check that the key is a secp256k1 key. If a provider plugin returned it, report it to the plugin. |
| `core.key.spki-parse`         | reason | `the public key could not be parsed as SubjectPublicKeyInfo`                            | The provider returned a PEM or DER public key that Node.js cannot read.                                    | If it repeats, report it to the provider plugin.                                                  |
| `core.key.spki-curve`         | reason | `expected a secp256k1 key, got {keyType} {curve}`                                       | The provider returned the public key of another key type or curve.                                         | Use a secp256k1 key, as the provider's setup guide creates it.                                    |
| `core.key.coordinate-missing` | reason | `the key has no "{coordinate}" coordinate`                                              | The provider returned a JSON Web Key without its `x` or `y` coordinate.                                    | If it repeats, report it to the provider plugin.                                                  |
| `core.key.coordinate-long`    | reason | `the "{coordinate}" coordinate is longer than 32 bytes`                                 | A JSON Web Key coordinate is too long for secp256k1.                                                       | Check that the key is a secp256k1 key.                                                            |
| `core.key.invalid-address`    | reason | `{address} is not a valid Ethereum address`                                             | A value is not `0x` and 40 hex digits, or it is mixed-case with a wrong EIP-55 checksum.                   | Check the address for a typo, or write it in lowercase.                                           |

### Signatures

| Id                                      | Kind   | Message                                                                                   | Cause                                                                                                                                                           | Fix                                                                                                        |
| --------------------------------------- | ------ | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `core.signature.format`                 | reason | `unsupported signature format; expected der or compact`                                   | A provider plugin returned a signature in a format the core does not read.                                                                                      | Report it to the provider plugin.                                                                          |
| `core.signature.compact-length`         | reason | `expected a 64-byte compact signature, got {length} bytes`                                | The provider returned an `r \|\| s` signature of the wrong length.                                                                                              | If it repeats, report it.                                                                                  |
| `core.signature.parse`                  | reason | `the {format} signature could not be parsed`                                              | The provider returned DER or compact bytes that are not a valid ECDSA signature.                                                                                | If it repeats, report it.                                                                                  |
| `core.signature.scalar-type`            | reason | `r and s must be bigints`                                                                 | A provider plugin returned a signature as `{ r, s }` whose values are not `bigint`, for example JavaScript numbers, which cannot hold a 256-bit scalar exactly. | Report it to the provider plugin.                                                                          |
| `core.signature.range`                  | reason | `r or s is outside the range [1, n - 1]`                                                  | A signature's `r` or `s` is 0, or not below the secp256k1 curve order, so it cannot be valid.                                                                   | For a signature from a provider, run again; for one given to `kms verify`, check that it was copied whole. |
| `core.signature.no-recovery`            | reason | `the signature does not recover to the expected public key`                               | No recovery bit gives back the key's public key: the signature is from another key, or over other data.                                                         | Check that the key id names the key you expect.                                                            |
| `core.signature.no-verify`              | reason | `the signature does not verify against the expected public key`                           | The signature does not verify against the key's public key over the digest.                                                                                     | Check that the key id names the key you expect.                                                            |
| `core.signature.hex`                    | reason | `the signature must be 0x-prefixed hex`                                                   | The signature given to `kms verify` does not start with `0x` or has a character that is not hex.                                                                | Pass the 65-byte signature as `0x` and 130 hex digits.                                                     |
| `core.signature.rpc-length`             | reason | `expected a 65-byte signature (r \|\| s \|\| v, 130 hex digits), got {digits} hex digits` | The signature given to `kms verify` is not 65 bytes long.                                                                                                       | Pass the whole `r \|\| s \|\| v` signature, as `eth_sign` and `kms sign` print it.                         |
| `core.signature.v`                      | reason | `v must be 0 or 1, 27 or 28, or 35 or more (EIP-155), got {v}`                            | The last byte of the signature is not a recovery id in any form Ethereum uses.                                                                                  | Check that the signature was copied whole and is an Ethereum signature.                                    |
| `core.signature.no-public-key`          | reason | `no public key recovers from the signature`                                               | The signature's `r` is not the x coordinate of a curve point, so no signer can be recovered.                                                                    | Check that the signature was copied whole.                                                                 |
| `core.signature.digest-length`          | reason | `expected a 32-byte digest, got {length} bytes`                                           | A signature check was asked to work on a digest that is not 32 bytes.                                                                                           | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.      |
| `core.signature.not-configured-address` | reason | `the signature does not recover to the configured address`                                | A provider that reports only an address signed, and no recovery bit gives the `address` pin: the key is not the one the pin names.                              | Check the key id and the `address` pin.                                                                    |

### Accounts

| Id                                        | Kind   | Message                                                                   | Cause                                                                                                                                                                                                                                                                      | Fix                                                                                                            |
| ----------------------------------------- | ------ | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `core.accounts.same-account`              | error  | `{name} and {other} are the same account ({address}); list each key once` | Two keys of the network give the same address, for example an alias and the key ARN it points to.                                                                                                                                                                          | Remove one of them from the network's `kmsAccounts` or from `--kms`.                                           |
| `core.accounts.unknown-account-hint`      | reason | `The KMS account on this network is {list}.`                              | A signing request named an account that is neither a KMS account nor one of the node's accounts. The plugin appends this sentence to the error from Hardhat or the node, so you can see which account it signs for. `{list}` is the address, or the first ten and a count. | Send from the address listed, or add the key of the account you meant to the network's `kmsAccounts`.          |
| `core.accounts.unknown-account-hint-many` | reason | `The KMS accounts on this network are {list}.`                            | As above, for a network with several KMS accounts. `{list}` holds the first ten addresses, then how many more there are.                                                                                                                                                   | Send from one of the addresses listed, or add the key of the account you meant to the network's `kmsAccounts`. |
| `core.accounts.already-listed`            | error  | `{name} is already {path}{named}; use one of them`                        | A `--kms` key names the same KMS key as one of the network's `kmsAccounts`. `{path}` is that entry's place, such as `networks.sepolia.kmsAccounts[0]`, and `{named}` adds its name in brackets when it has one.                                                            | Drop `--kms`, or remove the key from the network's `kmsAccounts`.                                              |
| `core.accounts.address-bytes`             | error  | `pass the address as the hex string {address}, not as a byte array`       | An `eth_sign`, `personal_sign` or `eth_signTypedData_v4` request names a KMS account as 20 bytes (a `Buffer` or a `Uint8Array`). Hardhat's simulated network and JSON-RPC nodes take the address only as a hex string. Nothing was signed.                                 | Pass the address as a 0x-prefixed hex string, for example with viem's `bytesToHex`.                            |

### Transactions

| Id                                  | Kind  | Message                                                                                                                                                                                                                                                     | Cause                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Fix                                                                                                                                                                                                                   |
| ----------------------------------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `core.tx.not-object`                | error | `the transaction must be an object`                                                                                                                                                                                                                         | The first parameter of `eth_sendTransaction` or `eth_signTransaction` is not an object.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Pass the transaction as an object of `eth_sendTransaction` fields.                                                                                                                                                    |
| `core.tx.self-authorization-nonce`  | error | `authorizationList[{index}] is signed by the sender for nonce {nonce}, but the final transaction requires nonce {expected}; nothing was signed`                                                                                                             | EIP-7702 increments the sender nonce before processing authorizations. Each valid self-authorization increments it again. The authorization nonce does not match.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | Choose the transaction nonce explicitly and sign the self-authorization for that nonce plus 1. Use consecutive nonces for additional self-authorizations, all below 2^64 - 1.                                         |
| `core.tx.self-authorization-chain`  | error | `authorizationList[{index}] is signed by the sender for chain {requested}, but the transaction is for chain {chainId}; nothing was signed`                                                                                                                  | A self-authorization names another chain. The node would skip it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | Sign the authorization for the transaction chain, or deliberately use chain 0.                                                                                                                                        |
| `core.tx.authorization-fees`        | error | `fee history could not be read; EIP-7702 needs EIP-1559 fees. Set maxFeePerGas and maxPriorityFeePerGas explicitly`                                                                                                                                         | Automatic EIP-1559 fee estimation is unavailable for a transaction with an authorization list. A legacy gas price cannot fund an EIP-7702 transaction.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Retry when the node can serve eth_feeHistory, or provide both EIP-1559 fee fields explicitly.                                                                                                                         |
| `core.tx.blob`                      | error | `blob transactions (EIP-4844) cannot be signed with KMS accounts; send them from another account`                                                                                                                                                           | The transaction has blobs, blob versioned hashes, `maxFeePerBlobGas` or type 3 (`0x3` in any case or with leading zeros, the number 3, `"3"` or `eip4844`, with or without surrounding whitespace). The plugin does not sign blob transactions. This check runs before the checks of `core.tx.unsupported-type` and `core.tx.type-mismatch`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | Send blob transactions from another account.                                                                                                                                                                          |
| `core.tx.unsupported-type`          | error | `transaction type {type} is not supported; KMS accounts sign types 0x0, 0x1, 0x2 and 0x4. Nothing was signed.`                                                                                                                                              | The transaction's `type` is a number other than 0, 1, 2, 3 or 4, such as a chain-specific type: Celo's fee-currency type `0x7b` (viem's Celo formatter sends it when `feeCurrency` is set), zkSync's EIP-712 type `0x71`, or the OP Stack deposit type `0x7e`. Before, such a request was signed as a plain transaction of the type its fee fields give, without its chain-specific fields. A `type` counts as a number when it is a hex quantity (either case, any leading zeros), a decimal string, a non-negative integer or a bigint, with or without surrounding whitespace. Any other `type`, such as viem's `"legacy"`, is ignored: the fields decide. The check runs before any request to the node.                                                                                                                                                                                                                            | Send the transaction from another account, or as type `0x0`, `0x1`, `0x2` or `0x4`.                                                                                                                                   |
| `core.tx.null-field`                | error | `the transaction's {field} is null; set a value or leave the field out. Nothing was signed.`                                                                                                                                                                | The transaction sets `gasPrice`, `maxFeePerGas`, `maxPriorityFeePerGas`, `accessList` or `authorizationList` to `null`, and the fill would not replace it. These fields take a value or are left out; `null` is neither. Before, such a request failed with a raw schema error. One `null` is still accepted, as Hardhat accepts it: with the network's `gasPrice` set to `"auto"`, no `gasPrice` and the other EIP-1559 field left out, a `null` `maxFeePerGas` or `maxPriorityFeePerGas` is filled like an absent one. The check runs after those of `core.tx.blob` and `core.tx.unsupported-type`, and before `core.tx.type-mismatch` and any request to the node. `{field}` is the first such field, in that order.                                                                                                                                                                                                                 | Set the field to a value, or leave it out to let the plugin fill it.                                                                                                                                                  |
| `core.tx.type-mismatch`             | error | `the transaction asks for type {requested}, but its fields make it type {actual}. Nothing was signed. {hint}`                                                                                                                                               | The transaction's `type` disagrees with the fee fields the caller set: `gasPrice`, `maxFeePerGas` or `maxPriorityFeePerGas`. The fields make it type 0x4 with an `authorizationList`, else 0x2 with an EIP-1559 fee field, else 0x1 with an `accessList`, else 0x0. For example, type `0x2` with `gasPrice` would be signed as legacy. Type `0x1` with `gasPrice` and no `accessList` is not a mismatch: it is signed as type 0x1 with an empty access list. A `type` with no fee field is not checked: the plugin fills the fees and the type follows them. A `null` fee or list field fails earlier, with `core.tx.null-field`, except a lone `null` EIP-1559 fee field that the automatic fee fill replaces: it counts as an EIP-1559 fee field, so `type: "0x0"` with `maxFeePerGas: null` is a mismatch. The check runs before any request to the node. `{hint}` says what to change, naming only the fields the transaction sets. | Set the fee fields of the type asked for (`gasPrice` for 0x0 and 0x1, `maxFeePerGas` and `maxPriorityFeePerGas` for 0x2 and 0x4), add an `authorizationList` for type 0x4, or remove `type` to let the fields decide. |
| `core.tx.no-gas`                    | error | `the transaction has no gas limit`                                                                                                                                                                                                                          | The filled transaction has no gas limit. The fill always sets one, so this is a guard.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                 |
| `core.tx.wrong-chain`               | error | `the transaction is for chain {requested}, but this network is chain {chainId}`                                                                                                                                                                             | The transaction's `chainId` differs from the chain of the network it is sent on. Nothing was signed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Remove `chainId` from the transaction, or send it on the network of that chain.                                                                                                                                       |
| `core.tx.no-latest-block`           | error | `the node returned no latest block`                                                                                                                                                                                                                         | The node answered `eth_getBlockByNumber("latest")` with something other than a block.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Check the network's RPC URL and that the node is synced.                                                                                                                                                              |
| `core.tx.no-block-gas-limit`        | error | `the {blockTag} block has no gasLimit`                                                                                                                                                                                                                      | The node's block, read to cap the gas limit, has no `gasLimit` field.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Check the network's RPC URL, or set `gas` on the transaction.                                                                                                                                                         |
| `core.tx.authorization-scalar`      | error | `authorizationList[{index}].{field} must be between 1 and the secp256k1 curve order minus 1`                                                                                                                                                                | An EIP-7702 authorization's `r` or `s` is 0 or not below the curve order, so the signature cannot be valid. Nothing was sent.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | Sign the authorization again, for example with `kms sign-auth`.                                                                                                                                                       |
| `core.tx.not-plain-data`            | error | `the transaction must be plain data (JSON values, bigints and byte arrays)`                                                                                                                                                                                 | The request holds a value that `structuredClone` cannot copy, such as a function, a symbol or a getter that throws.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | Pass plain values: strings, numbers, bigints, byte arrays, arrays and objects.                                                                                                                                        |
| `core.tx.from-bytes`                | error | ``pass `from` as the hex string {address}, not as a byte array``                                                                                                                                                                                            | The transaction's `from` names a KMS account as 20 bytes (a `Buffer` or a `Uint8Array`). Hardhat's simulated network and JSON-RPC nodes take `from` only as a hex string. Nothing was signed or sent.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Pass `from` as a 0x-prefixed hex string, for example with viem's `bytesToHex`.                                                                                                                                        |
| `core.tx.node-answer-not-string`    | error | `the node's {what} answer is not a string`                                                                                                                                                                                                                  | The node answered a fee or gas request with something other than a hex string.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | Check the network's RPC URL; the node may not be an Ethereum JSON-RPC node.                                                                                                                                           |
| `core.tx.no-fee`                    | error | `the transaction has no gasPrice, maxFeePerGas or maxPriorityFeePerGas`                                                                                                                                                                                     | The filled transaction has no fee field. The fill always sets one, so this is a guard Hardhat has too.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                 |
| `core.tx.gas-price-7702`            | error | `an EIP-7702 transaction (authorizationList) cannot have a gasPrice`                                                                                                                                                                                        | The transaction has an `authorizationList` and a `gasPrice`. EIP-7702 transactions use EIP-1559 fees.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Remove `gasPrice`, or set `maxFeePerGas` and `maxPriorityFeePerGas` instead.                                                                                                                                          |
| `core.tx.both-fees`                 | error | `the transaction cannot have both gasPrice and maxFeePerGas or maxPriorityFeePerGas`                                                                                                                                                                        | The transaction mixes legacy and EIP-1559 fee fields.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Keep `gasPrice` alone, or `maxFeePerGas` with `maxPriorityFeePerGas`.                                                                                                                                                 |
| `core.tx.no-max-fee`                | error | `the transaction has maxPriorityFeePerGas but no maxFeePerGas`                                                                                                                                                                                              | The filled transaction has `maxPriorityFeePerGas` without `maxFeePerGas`. The fill completes the missing field, so this is a guard Hardhat has too.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                 |
| `core.tx.no-priority-fee`           | error | `the transaction has maxFeePerGas but no maxPriorityFeePerGas`                                                                                                                                                                                              | The filled transaction has `maxFeePerGas` without `maxPriorityFeePerGas`. The fill completes the missing field, so this is a guard Hardhat has too.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                 |
| `core.tx.creation-no-data`          | error | `` a contract creation (no `to`) needs `data` ``                                                                                                                                                                                                            | The transaction has neither `to` nor `data`, so it would create a contract with no code.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Set `to` to send to an account, or `data` to deploy a contract.                                                                                                                                                       |
| `core.tx.both-max-fees`             | error | `an EIP-1559 or EIP-7702 transaction needs both maxFeePerGas fields`                                                                                                                                                                                        | The transaction to sign is an EIP-1559 or EIP-7702 transaction without both fee fields. The fill always sets both, so this is a guard.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                 |
| `core.tx.no-recovery`               | error | `the signed transaction does not recover to {from}; nothing was sent`                                                                                                                                                                                       | The final check of a signed transaction found another sender than the account. The transaction is not sent.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                 |
| `core.tx.not-from`                  | error | `the filled transaction is not from {from}`                                                                                                                                                                                                                 | After the fill, the transaction's `from` is not the account that was asked to sign it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                 |
| `core.tx.send-waiters-full`         | error | `Too many sends from {account} are waiting: the limit is {limit}. This send was not signed or sent.`                                                                                                                                                        | Sends from one account on one chain run one at a time, and too many were already waiting.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | Wait for earlier sends before starting more, for example by awaiting each one.                                                                                                                                        |
| `core.tx.send-stalled`              | error | `A send from {account} waited {seconds} s for the account's earlier sends, and none finished. This send was not signed or sent.`                                                                                                                            | An earlier send from the same account is stuck, for example waiting for a KMS approval or a node that does not answer.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Find the earlier send that does not finish, and send this one again.                                                                                                                                                  |
| `core.tx.send-reentrant`            | error | `A send from {account} was made from inside an earlier send from the same account on that chain, for example by a hook during its fill or broadcast. It would wait for itself, so it was not signed or sent.`                                               | Code that runs during a send, such as a network hook, sent from the same account again.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Send the second transaction after the first one returns.                                                                                                                                                              |
| `core.tx.raw-send-reentrant`        | error | `A raw transaction from {account} was sent from inside an earlier send from the same account on that chain, for example by a hook during its fill or broadcast. It would wait for itself, so it was not sent.`                                              | Code that runs during a send, such as a network hook, sent a transaction that the same account signed outside the plugin, for example with a connection.kms.getAccount account.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Send the second transaction after the first one returns.                                                                                                                                                              |
| `core.tx.wallet-send-refused`       | error | `wallet_sendTransaction is not available for the KMS account {address}. Send with eth_sendTransaction, which the plugin signs.`                                                                                                                             | A `wallet_sendTransaction` request named a KMS account as `from`. The plugin sends a KMS account's transactions through `eth_sendTransaction` only, so it answers this method with JSON-RPC error -32601 (method not found) and does not pass it to the node. viem sends it once after an `eth_sendTransaction` error such as -32000, and then throws the first error.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | If viem sent it, nothing: viem throws the `eth_sendTransaction` error instead. If your code sends it, send `eth_sendTransaction`.                                                                                     |
| `core.tx.wallet-send-calls-refused` | error | `wallet_sendCalls is not available for the KMS account {address}. Pass experimental_fallback: true to viem's sendCalls, or send each call as its own transaction.`                                                                                          | A `wallet_sendCalls` (EIP-5792) request named a KMS account as `from`. The plugin sends a KMS account's transactions through `eth_sendTransaction` only, so it answers this method with JSON-RPC error -32601 (method not found) and does not pass it to the node. viem's `sendCalls` sends it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Pass `experimental_fallback: true` to viem's `sendCalls`: on -32601 viem sends each call with `eth_sendTransaction`, and the KMS key signs each one. Or send each call yourself with `sendTransaction`.               |
| `core.tx.connection-closed`         | error | `{method}: the connection to network {network} closed before the transaction was broadcast, so nothing was sent. Send it again on an open connection`                                                                                                       | `connection.close()` ran while the send waited for its KMS signature or for an earlier send from the same account. A closed connection keeps no record of the account's nonces, so the plugin does not broadcast through it: a send on another connection could take the same nonce.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Wait for each send to return before you close its connection, or send again on an open connection from `network.create()`.                                                                                            |
| `core.tx.outcome-unknown`           | error | `{method}: transaction {hash} was handed to the node, but no answer came back ({cause}). It may still be mined: look it up by its hash before sending another transaction. Repeating the same request within {seconds} s sends the same transaction again.` | The signed transaction reached the node, but the connection failed before the node answered, so the plugin cannot tell whether it was accepted.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Look the hash up on the network. If it is not there, repeat the request: within the time the message gives, the same signed transaction is sent again.                                                                |

### Library accounts

| Id                                 | Kind  | Message                                                                                                                                                                                                                                   | Cause                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Fix                                                                                                                                                                                                                       |
| ---------------------------------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `core.account.nonce-reentrant`     | error | `A transaction of the library account {account} was started from inside an earlier send from the same account on that chain, for example by a hook during its fill or broadcast. It would wait for itself, so it was not signed or sent.` | Code that runs during a send, such as a network hook, sent a transaction with a connection.kms.getAccount account of the same address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Send the second transaction after the first one returns.                                                                                                                                                                  |
| `core.account.viem-missing`        | error | `connection.kms.getAccount needs the viem package, which could not be loaded ({reason}). Install viem in the project`                                                                                                                     | `getAccount` returns a viem account, and viem, an optional peer dependency of hardhat-kms, is not installed in the project, or failed to load.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Install viem in the project with your package manager (for example `npm install --save-dev viem`, `pnpm add -D viem` or `yarn add -D viem`). Nothing else in the plugin needs it.                                         |
| `core.account.viem-too-old`        | error | `connection.kms.getAccount needs viem {floor} or later, and the project has viem {installed}. Upgrade viem to {floor} or later`                                                                                                           | The account's nonce manager relies on viem calling its `reset` after every failed send, and only after a `consume`. With viem 2.49.3 and earlier, a failed library send never resets, so the account's next send through the plugin waits up to 60 s. With viem 2.50.3 to 2.55.11, a `reset` can follow a send that never asked for a nonce and end another send's hold, so a send through the plugin can take a nonce that send still needs. When the project asks for a viem that no release in the peer range satisfies, such as `2.55.11` or `~2.54.0`, npm 11.15.0 stops the install with `ERESOLVE` unless it runs with `--legacy-peer-deps`; pnpm 12.8.1, Yarn 1.22.22 and Yarn 4.18.1 install the older release. When the project's range overlaps the peer range but its lockfile holds an older release, such as `^2.47.6` from Hardhat's viem template with 2.52.2 locked, npm 11.15.0 installed with exit code 0 and moved viem to the newest release (2.57.2 when measured), and pnpm 12.8.1, Yarn 1.22.22, Yarn 4.18.1 and npm 11.15.0 with `--legacy-peer-deps` kept the locked 2.52.2. | Upgrade viem in the project to 2.55.13 or later, the floor of its peer range, with your package manager (for example `npm install --save-dev viem@^2.55.13`, `pnpm add -D viem@^2.55.13` or `yarn add -D viem@^2.55.13`). |
| `core.account.connection-closed`   | error | `the connection to network {network} is closed, so its KMS accounts no longer sign. Get the account from an open connection`                                                                                                              | `getAccount` or a method of the account it returned was called after `connection.close()`. A closed connection's library accounts refuse to sign, before any KMS call.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Call `getAccount` on an open connection, from `network.create()`, and use that account.                                                                                                                                   |
| `core.account.cancelled`           | error | `the signal given to getAccount has aborted, so the account makes no more KMS calls. Call getAccount with a new signal to sign again`                                                                                                     | `getAccount`, or a method of the account it returned, was called after the `signal` passed in its options aborted. The account refuses before any KMS call and reserves no nonce.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Call `getAccount` again, with a signal that has not aborted or with none.                                                                                                                                                 |
| `core.account.option`              | error | `{name} is not an option of getAccount; the options are rawSign, allowChainZeroAuthorization and signal`                                                                                                                                  | The options object of `getAccount` has a key the plugin does not know, often a typo. It is refused so that a misspelled option is not silently ignored.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Correct or remove the option.                                                                                                                                                                                             |
| `core.account.field`               | error | `{field} must be {expected}`                                                                                                                                                                                                              | A value given to `getAccount` or to one of the account's methods does not have the type or form viem gives it. Nothing was signed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | Pass the value in the form the message names, as viem's own actions pass it.                                                                                                                                              |
| `core.account.not-kms`             | error | `{address} is not a KMS account of network {network}.{accounts}`                                                                                                                                                                          | `getAccount` was given an address that none of the connection's KMS keys has. The message lists the addresses it has.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Pass one of the listed addresses, or add the key to the network's `kmsAccounts`.                                                                                                                                          |
| `core.account.tx-type`             | error | `transaction type {type} is not signed: KMS accounts sign legacy, eip2930, eip1559 and eip7702 transactions`                                                                                                                              | The account's `signTransaction` got a transaction whose `type` is not one it signs, such as a chain-specific deposit type. Nothing was signed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Send the transaction from another account, or as one of the listed types.                                                                                                                                                 |
| `core.account.tx-no-type`          | error | `the transaction's type cannot be told from its fields: set type, gasPrice or maxFeePerGas`                                                                                                                                               | The transaction has no `type` and no fee field, so neither viem nor the plugin can tell how to encode it. viem's actions always set one.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | Set `type`, or the fee fields of the type you want.                                                                                                                                                                       |
| `core.account.tx-no-chain`         | error | `the transaction has no chainId; a KMS account signs only for its network's chain`                                                                                                                                                        | The account's `signTransaction` got a transaction without `chainId`. A transaction without one is valid on every chain, so it is refused.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | Set `chainId` to the network's chain. viem's actions set it.                                                                                                                                                              |
| `core.account.tx-wrong-chain`      | error | `the transaction is for chain {requested}, but network {network} is chain {chainId}`                                                                                                                                                      | The transaction's `chainId` is another chain than the one of the connection the account comes from. Nothing was signed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Get the account from a connection to that chain's network.                                                                                                                                                                |
| `core.account.tx-invalid`          | error | `the transaction cannot be encoded: {reason}`                                                                                                                                                                                             | The plugin's transaction encoder refused a value of the transaction, for example a number too large for its field. Nothing was signed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Correct the value the reason names.                                                                                                                                                                                       |
| `core.account.serializer-failed`   | error | `{serializer} failed on the transaction ({errorName}), so it was not signed`                                                                                                                                                              | Before signing, the account encodes the transaction with viem's serializer, or with the chain serializer viem passed, to compare it with its own encoding. That serializer threw.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Check the transaction's fields: viem refuses values its types do not allow.                                                                                                                                               |
| `core.account.serializer-mismatch` | error | `{serializer} encodes the transaction differently from hardhat-kms, so it was not signed`                                                                                                                                                 | The account signs the transaction as the plugin encodes it, and refuses when viem's serializer, or the chain serializer viem passed, encodes other bytes. A chain with its own transaction format, such as a field the plugin does not encode, causes this.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | Send the transaction from another account. If the chain uses the standard transaction format, open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the transaction's fields.                              |
| `core.account.auth-chain-zero`     | error | ``an authorization for chain 0 is valid on every chain where the account's nonce matches. Pass `allowChainZeroAuthorization: true` to getAccount to sign it``                                                                             | The account's `signAuthorization` was asked for a chain-0 authorization, which any chain accepts.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Sign for the network's chain, or get the account with `allowChainZeroAuthorization: true` if a chain-0 authorization is intended.                                                                                         |
| `core.account.auth-wrong-chain`    | error | `the authorization is for chain {requested}, but network {network} is chain {chainId}`                                                                                                                                                    | The account's `signAuthorization` was asked for another chain than the one of the connection the account comes from.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Get the account from a connection to that chain's network, or run `kms sign-auth --chain`.                                                                                                                                |
| `core.account.auth-no-recovery`    | error | `the authorization does not recover to the account's address`                                                                                                                                                                             | The account checks the authorization it returns against its address, and the check failed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                     |

### Typed data

| Id                               | Kind   | Message                                                                                                                                                    | Cause                                                                                                                                                                                                                                                | Fix                                                                                                                        |
| -------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `core.typed-data.invalid`        | error  | `the typed data is invalid: {reason}`                                                                                                                      | The EIP-712 typed data does not have the shape EIP-712 requires. The reason is one of the typed-data reasons below.                                                                                                                                  | Fix the typed data as the reason says.                                                                                     |
| `core.typed-data.not-json`       | error  | `the typed data is not valid JSON`                                                                                                                         | Typed data given as a string, as `eth_signTypedData_v4` takes it, is not JSON.                                                                                                                                                                       | Pass `JSON.stringify(typedData)`, or the typed data object.                                                                |
| `core.typed-data.unreadable`     | error  | `the typed data could not be read ({errorName}); it may be nested too deeply`                                                                              | Reading the typed data JSON failed with something other than a syntax error, usually a stack overflow on very deep nesting.                                                                                                                          | Flatten the typed data.                                                                                                    |
| `core.typed-data.chain-mismatch` | error  | ``the typed data is for chain {domainChain}, but {name} is chain {chainId}. Set `kms.allowCrossChainTypedData: true` to sign typed data for other chains`` | The typed data's `domain.chainId` is another chain than the network's. A signature for it could act on that chain.                                                                                                                                   | Sign it on the network of that chain, or set `kms.allowCrossChainTypedData: true` if signing for other chains is intended. |
| `core.typed-data.plain-data`     | reason | `the typed data must be plain data (JSON values and bigints)`                                                                                              | The typed data holds a value that `structuredClone` cannot copy, such as a function, a symbol or a getter that throws.                                                                                                                               | Pass plain values.                                                                                                         |
| `core.typed-data.object`         | reason | `the typed data must be an object`                                                                                                                         | The typed data is not an object.                                                                                                                                                                                                                     | Pass an object with `types`, `primaryType`, `domain` and `message`.                                                        |
| `core.typed-data.types`          | reason | `` `types` must map each type name to a list of {name, type} ``                                                                                            | The typed data's `types` is missing or not an object.                                                                                                                                                                                                | Give `types` an entry per struct, each a list of `{ name, type }` fields.                                                  |
| `core.typed-data.type-fields`    | reason | `` `types.{typeName}` must be a list of {name, type} ``                                                                                                    | One entry of `types` is not a list of `{ name, type }` fields with string values.                                                                                                                                                                    | Fix the struct the message names.                                                                                          |
| `core.typed-data.shape`          | reason | `` the typed data needs a string `primaryType` and object `domain` and `message` ``                                                                        | The typed data lacks `primaryType`, `domain` or `message`, or one has the wrong type.                                                                                                                                                                | Add the missing field.                                                                                                     |
| `core.typed-data.encoder`        | reason | `{message}`                                                                                                                                                | The EIP-712 encoder refused the typed data, for example for an unknown type or a value that does not fit its type. The message is the encoder's own, cut to 200 characters, ending in `...`, because it can quote a whole value.                     | Fix the type or value the message names.                                                                                   |
| `core.typed-data.unsafe-integer` | reason | `a number {where} is above 2^53 - 1, so JSON cannot hold it exactly; write it as a string`                                                                 | The typed data JSON has an integer too large for a JavaScript number, which would be rounded and signed as another value. The message names the key, cut to 40 characters, and never the number, since the file may be another one given by mistake. | Write large integers, such as `uint256` amounts, as decimal or hex strings.                                                |

### Chains

| Id                      | Kind  | Message                                                                        | Cause                                                                                                                       | Fix                                                                         |
| ----------------------- | ----- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `core.chain.id-invalid` | error | `{what} is not a chain id: expected a non-negative integer, got {value}`       | A chain id, such as the typed data's `domain.chainId` or `--chain`, is not a non-negative integer.                          | Use a decimal or `0x` hex integer, such as `11155111`.                      |
| `core.chain.not-hex`    | error | `the node answered eth_chainId with {answer}, not a hex quantity`              | The network's node answered `eth_chainId` with something other than a hex number.                                           | Check the network's RPC URL; the node may not be an Ethereum JSON-RPC node. |
| `core.chain.mismatch`   | error | `the network config sets chainId {configured}, but the node reports {chainId}` | The network's `chainId` in the Hardhat config differs from the chain its node is on, so the URL may point at another chain. | Fix the network's `url` or its `chainId`.                                   |

### Tasks

| Id                                        | Kind   | Message                                                                                                                                                           | Cause                                                                                                                                                                                                                                                                    | Fix                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ----------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `core.task.unknown-network`               | error  | `unknown network "{name}"`                                                                                                                                        | `kms accounts` was run with a `--network` that the Hardhat config does not define.                                                                                                                                                                                       | Use a network from `networks` in the config.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `core.task.not-hex`                       | error  | `{what} is not 0x-prefixed hex with an even number of digits`                                                                                                     | A task argument that starts with `0x` is read as bytes, and this one has an odd number of digits or a character that is not hex.                                                                                                                                         | Fix the hex, or drop the `0x` to sign the text as UTF-8.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `core.task.typed-data-file-unreadable`    | error  | `cannot read the typed data file {file} ({errorName})`                                                                                                            | `--from-file` names a file that cannot be read, for example because it does not exist.                                                                                                                                                                                   | Check the path, relative to the directory the task runs in.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `core.task.key-ambiguous`                 | error  | `"{name}" names more than one key, from {sources}; rename the key in kms.keys`                                                                                    | A key in `kms.keys` has the same name as a `--kms` key, such as `AWS_KMS_KEY_ID`.                                                                                                                                                                                        | Rename the key in `kms.keys`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `core.task.unknown-key-none`              | error  | `unknown key "{name}". No KMS keys are configured: add them to kms.keys or a network's kmsAccounts, or pass --kms.`                                               | A `kms` task was given a key name, but no keys are configured.                                                                                                                                                                                                           | Add keys to the config, or pass `--kms` with the provider's environment variables.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `core.task.unknown-key-suggested`         | error  | `unknown key "{name}". Did you mean "{suggestions}"? Known keys: {known}.`                                                                                        | A `kms` task was given a key name that differs from a configured one only in case. Names are case-sensitive.                                                                                                                                                             | Use the suggested name.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `core.task.unknown-key`                   | error  | `unknown key "{name}". Known keys: {known}.`                                                                                                                      | A `kms` task was given a key name that is not configured.                                                                                                                                                                                                                | Use one of the names listed. `npx hardhat kms accounts` lists every key.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `core.task.sign-no-recovery`              | error  | `the signature does not recover to the key's address`                                                                                                             | `kms sign` checks the signature it prints against the key's address, and the check failed.                                                                                                                                                                               | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `core.task.from-file-needs-data`          | error  | `--from-file requires --data`                                                                                                                                     | `--from-file` reads typed data from a file, so it works only with `--data`.                                                                                                                                                                                              | Add `--data`, or pass the message itself without `--from-file`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `core.task.no-hash-with-data`             | error  | `--no-hash cannot be combined with --data`                                                                                                                        | `kms sign` signs a raw digest with `--no-hash` and typed data with `--data`, not both.                                                                                                                                                                                   | Drop one of the two options.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `core.task.chain-options-need-data`       | error  | `--chain and --allow-cross-chain apply only to --data`                                                                                                            | The chain check of `kms sign` applies only to typed data.                                                                                                                                                                                                                | Add `--data`, or drop `--chain` and `--allow-cross-chain`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `core.task.sign-chain-and-network`        | error  | `pass --chain or --network, not both`                                                                                                                             | `kms sign --data` compares the typed data's chain with `--chain` or with the network's, and both were given.                                                                                                                                                             | Keep one. `--network` can also come from the `HARDHAT_NETWORK` environment variable.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `core.task.no-hash-digest-length`         | error  | `--no-hash needs a {expected}-byte digest, got {length} bytes`                                                                                                    | `kms sign --no-hash` signs a digest as given, and the hex is not 32 bytes.                                                                                                                                                                                               | Pass a 32-byte hash as `0x` and 64 hex digits.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `core.task.sign-no-chain`                 | error  | `the typed data is for chain {domainChain}, and there is no chain to compare it with. Pass --network or --chain, or --allow-cross-chain to sign it for any chain` | The typed data names a chain, and `kms sign` was given neither `--network` nor `--chain` to check it against.                                                                                                                                                            | Pass the chain the signature is for, or `--allow-cross-chain`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `core.task.sign-chain-mismatch`           | error  | `the typed data is for chain {domainChain}, but {name} is chain {chainId}. Pass --allow-cross-chain to sign it for another chain`                                 | The typed data's `domain.chainId` differs from `--chain` or the network's chain.                                                                                                                                                                                         | Use the network or `--chain` of that chain, or `--allow-cross-chain` if signing for another chain is intended.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `core.task.verify-invalid-signature`      | error  | `invalid signature: {reason}`                                                                                                                                     | The signature given to `kms verify` cannot be read or recovered. The reason is one of the signature reasons above.                                                                                                                                                       | Pass the 65-byte `r \|\| s \|\| v` signature as `0x` and 130 hex digits.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `core.task.verify-address-and-key`        | error  | `pass either --address or --key, not both`                                                                                                                        | `kms verify` compares the signer with one expected account, and both options were given.                                                                                                                                                                                 | Keep one of the two.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `core.task.verify-no-signer`              | error  | `pass the expected signer with --address <address> or --key <key>`                                                                                                | `kms verify` needs the account the signature should come from.                                                                                                                                                                                                           | Add `--address` or `--key`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `core.task.verify-address-invalid`        | error  | `--address: {reason}`                                                                                                                                             | `--address` is not a valid address.                                                                                                                                                                                                                                      | Check the address for a typo, or write it in lowercase.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `core.task.tx-file-unreadable`            | error  | `cannot read the transaction file {file} ({code})`                                                                                                                | `kms sign-tx` cannot read the file, for example `ENOENT` when it does not exist.                                                                                                                                                                                         | Check the path, relative to the directory the task runs in.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `core.task.tx-file-not-json`              | error  | `the transaction file {file} is not valid JSON at line {line}, column {column}`                                                                                   | The file given to `kms sign-tx` is not JSON, for example another file given by mistake. The message names where the JSON stops being valid and quotes none of the file, which could hold a secret.                                                                       | Fix the JSON. Quantities are strings, such as `"0x1"`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `core.task.tx-file-not-object`            | error  | `the transaction file {file} must hold one JSON object with eth_sendTransaction fields`                                                                           | The file holds an array, a string or another value instead of one transaction object.                                                                                                                                                                                    | Put one object in the file, such as `{ "to": "0x…", "value": "0x1" }`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `core.task.tx-file-checksum`              | error  | `{field} {value} has a wrong EIP-55 checksum, which usually means a typo. Check the address, or write it in lowercase.`                                           | A mixed-case address in the transaction file has a wrong EIP-55 checksum.                                                                                                                                                                                                | Check the address, or write it in lowercase.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `core.task.tx-file-unknown-fields`        | error  | `unknown transaction {fields}{hints}. The fields are those of eth_sendTransaction: {known}.`                                                                      | The transaction file has fields that `eth_sendTransaction` does not take, often a viem or ethers name such as `gasLimit`. `{fields}` is `field` or `fields` and the names; `{hints}` is empty or a bracketed list such as `(use gas instead of gasLimit)`.               | Rename or remove the fields; the message suggests the right name where it knows one.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `core.task.tx-file-not-quantity`          | error  | `{field} must be a hex quantity, such as "0x1", got {value}`                                                                                                      | A numeric field in the transaction file is not a `0x` hex string, for example a JSON number.                                                                                                                                                                             | Write it as a hex string.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `core.task.tx-file-type-not-quantity`     | error  | `type must be a hex quantity, such as "0x2"`                                                                                                                      | The transaction file's `type` is not a `0x` hex string.                                                                                                                                                                                                                  | Write it as a hex string, or remove it to let the fields decide the type.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `core.task.tx-file-unsupported-type`      | error  | `transaction type {type} is not supported; KMS accounts sign types 0x0, 0x1, 0x2 and 0x4`                                                                         | The transaction file asks for a type the plugin does not sign.                                                                                                                                                                                                           | Use type `0x0`, `0x1`, `0x2` or `0x4`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `core.task.tx-type-mismatch`              | error  | `the transaction asks for type {requested}, but its fields make it type {actual}; nothing was signed. Set the fee fields of type {requested}, or remove type.`    | The transaction file's `type` disagrees with its fee fields, for example type `0x2` with `gasPrice`.                                                                                                                                                                     | Set the fee fields of the type asked for, or remove `type`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `core.task.sign-tx-needs-network`         | error  | `--network is required: the transaction is filled on that network's node, and its chain id is checked against it`                                                 | `kms sign-tx` fills the nonce, gas and fees from a node, so it needs a network.                                                                                                                                                                                          | Pass `--network <name>`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `core.task.sign-tx-wrong-from`            | error  | `the transaction's from is {from}, but key {keyName} has the address {address}. Remove from, or name the key of that address.`                                    | The transaction file's `from` is not the address of the key the task signs with.                                                                                                                                                                                         | Remove `from`, or pass the key of that address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `core.task.auth-chain-zero`               | error  | `an authorization for chain 0 is valid on every chain where the account's nonce matches. Pass --force to sign it anyway`                                          | `kms sign-auth` was asked for a chain-0 authorization, which any chain accepts.                                                                                                                                                                                          | Pass the chain the authorization is for, or `--force` if a chain-0 authorization is intended.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `core.task.auth-nonce-too-large`          | error  | `the nonce {nonce} is too large: EIP-7702 needs one below 2^64 - 1`                                                                                               | The authorization's nonce does not fit EIP-7702's limit.                                                                                                                                                                                                                 | Pass the account's real nonce, or let the task read it with `--network`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `core.task.auth-no-recovery`              | error  | `the authorization does not recover to the key's address`                                                                                                         | `kms sign-auth` checks the authorization it prints against the key's address, and the check failed.                                                                                                                                                                      | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `core.task.auth-chain-and-network`        | error  | `pass --chain or --network, not both. --network can also come from the HARDHAT_NETWORK environment variable`                                                      | `kms sign-auth` takes the chain from `--chain` or from the network, and both were given.                                                                                                                                                                                 | Keep one; unset `HARDHAT_NETWORK` if it set the network.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `core.task.auth-no-chain`                 | error  | `pass --chain, or --network to sign for that network's chain`                                                                                                     | `kms sign-auth` needs the chain the authorization is for.                                                                                                                                                                                                                | Add `--chain` or `--network`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `core.task.auth-nonce-and-self-broadcast` | error  | `--nonce cannot be combined with --self-broadcast`                                                                                                                | `--self-broadcast` changes the nonce the task reads from the node, so it has no effect with `--nonce`.                                                                                                                                                                   | Pass the nonce the authorization needs with `--nonce` alone.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `core.task.auth-no-nonce`                 | error  | `pass --nonce, or --network to read the key's pending nonce`                                                                                                      | `kms sign-auth` needs the account's nonce, and has no network to read it from.                                                                                                                                                                                           | Add `--nonce` or `--network`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `core.task.auth-chain-too-large`          | error  | `--chain does not fit in 256 bits`                                                                                                                                | `--chain` is larger than any chain id.                                                                                                                                                                                                                                   | Pass the real chain id.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `core.task.auth-delegate-invalid`         | error  | `the delegate {delegate} is not an address: expected 0x and 40 hex digits, with a valid EIP-55 checksum if it is mixed-case`                                      | The delegate given to `kms sign-auth` is not an address, or its checksum is wrong.                                                                                                                                                                                       | Check the address for a typo, or write it in lowercase.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `core.task.auth-nonce-invalid`            | error  | `--nonce is not a nonce: expected a non-negative integer, got {value}`                                                                                            | `--nonce` is not a decimal or `0x` hex integer.                                                                                                                                                                                                                          | Pass a non-negative integer.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `core.task.auth-node-nonce`               | error  | `the node answered eth_getTransactionCount with something other than a nonce`                                                                                     | The network's node did not answer `eth_getTransactionCount` with a hex number.                                                                                                                                                                                           | Check the network's RPC URL, or pass `--nonce`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `core.task.balances-need-network`         | error  | `--balances reads balances on one network: pass --network <name>`                                                                                                 | `kms accounts --balances` was run without `--network`, so it has no node to ask.                                                                                                                                                                                         | Add `--network` with the network whose balances you want.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `core.task.balance-read-failed`           | reason | `could not read the balance: {reason}`                                                                                                                            | `kms accounts --balances` could not connect to the network, or the node did not answer `eth_getBalance` for the key's address. The row fails, and the task exits with code 1.                                                                                            | Check the network's RPC URL and that the node is reachable. The text after the colon says what failed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `core.task.balance-not-hex`               | error  | `the node answered eth_getBalance with {answer}, not a hex quantity`                                                                                              | The network's node answered `eth_getBalance` with something other than a hex number.                                                                                                                                                                                     | Check the network's RPC URL; the node may not be an Ethereum JSON-RPC node.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `core.task.check-sign-failed`             | reason | `the sign check failed: {reason}`                                                                                                                                 | `kms accounts --check-sign` asked the key to sign a random EIP-191 message, and the KMS refused or the signature did not recover to the key's address. Reading a public key and signing need different permissions, so a key can pass the plain check and fail this one. | Give the credentials the provider's sign permission: `kms:Sign` on AWS, `cloudkms.cryptoKeyVersions.useToSign` on Google Cloud. On Azure, the identity needs read and sign on the key, as step 2 of the Azure setup guide shows: `Microsoft.KeyVault/vaults/keys/read` and `Microsoft.KeyVault/vaults/keys/sign/action` in a custom role or the built-in Key Vault Crypto User role, the `get` and `sign` key permissions in an access policy, or `Microsoft.KeyVault/managedHsm/keys/read/action` and `Microsoft.KeyVault/managedHsm/keys/sign/action` on a Managed HSM. The text after the colon says what failed. |

### History

| Id                                       | Kind  | Message                                                                                                                                                                                 | Cause                                                                                                                                                                                                                                                                           | Fix                                                                                                                                 |
| ---------------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `core.history.time-invalid`              | error | `--{option} "{value}" is not a time. Use an ISO 8601 time with a time zone, such as 2026-10-02T09:00:00Z, a date such as 2026-10-02, or a duration before now, such as 30m, 6h or 7d`   | `kms history` was given a `--since` or `--until` it cannot read. A time without a time zone is refused, because it could mean any zone.                                                                                                                                         | Add `Z` or an offset such as `+02:00` to the time, or use a duration in `s`, `m`, `h` or `d`.                                       |
| `core.history.range-empty`               | error | `--since ({since}) must be before --until ({until})`                                                                                                                                    | The start of the range is not before its end. Without `--until`, the end is now, so a `--since` in the future fails too.                                                                                                                                                        | Swap the two values, or move `--since` back.                                                                                        |
| `core.history.until-future`              | error | `--until ({until}) is more than 5 minutes after now ({now})`                                                                                                                            | `kms history --until` names a time in the future. The log cannot hold events from then, and a range that ends later would look complete when it is not.                                                                                                                         | Leave `--until` out to read up to now, or check the date and its time zone.                                                         |
| `core.history.limit-range`               | error | `--limit must be an integer from 1 to {max}, got {limit}`                                                                                                                               | `kms history --limit` is 0, negative or above the maximum.                                                                                                                                                                                                                      | Use a smaller `--limit`, and narrow the range with `--since` and `--until` to see older events.                                     |
| `core.history.no-reader`                 | error | `no plugin reads the audit log of "{provider}" keys, so kms history cannot list this key's sign events`                                                                                 | No plugin in the Hardhat config implements the `kms.readSignHistory` hook for the key's provider. A third-party provider plugin may sign without offering a history reader.                                                                                                     | Read the provider's audit log with its own tools, or ask the provider plugin's authors to add a reader (see the provider contract). |
| `core.history.no-reader-builtin`         | error | ``no installed plugin reads {name} audit logs. The reader ships in {package}; install or update it to the same version as hardhat-kms, and add it to `plugins` in your Hardhat config`` | The key's provider is built in, but its provider package is not in `plugins`, or it is a version without a history reader.                                                                                                                                                      | Install the package the message names, at the same version as hardhat-kms, and add its plugin to `plugins`.                         |
| `core.history.read-failed`               | error | `reading the audit log failed ({errorName})`                                                                                                                                            | The history reader threw an error that is not one of the plugin's own. Only its class name is shown, since SDK messages can carry request details.                                                                                                                              | Run with `DEBUG=hardhat:kms:*` to see the step that failed, and check the provider's read permission.                               |
| `core.history.reader-invalid`            | error | `the history reader returned an invalid result: {problem}`                                                                                                                              | A provider plugin's `kms.readSignHistory` handler returned something that does not follow the contract, such as an event outside the range or a value for a field it lists as not logged.                                                                                       | Report it to the provider plugin; see the reader contract in the provider guide.                                                    |
| `core.history.access-denied`             | error | `cannot read the audit log: the credentials lack {permission}. Grant it, or run with credentials that have it`                                                                          | The provider refused to return log entries to the credentials in use. A reader never reports an empty history for a log it could not read.                                                                                                                                      | Grant the permission the message names to the identity that runs `kms history`. The provider setup guides list it.                  |
| `core.history.throttled`                 | error | `the audit log kept refusing requests as too frequent ({limit})`                                                                                                                        | The provider throttled the reads, and the reader's retries did not get through. Long ranges need many requests.                                                                                                                                                                 | Wait a minute and run again, or narrow the range with `--since` and `--until`, or lower `--limit`.                                  |
| `core.history.access-denied-unprintable` | error | `cannot read the audit log: the credentials lack a permission. The history reader named it in a form that could carry an id, so it is not shown; this is a bug in the reader`           | The provider refused to return log entries, and the history reader passed `auditLogAccessDenied` a permission with characters, a URL, an ARN, a resource path or a run of digits or hex that could be an account or key id. Such a value would be printed without `--show-ids`. | Grant the read permission that the provider setup guide lists, and report the bug to the provider plugin.                           |
| `core.history.throttled-unprintable`     | error | `the audit log kept refusing requests as too frequent. The history reader named the limit in a form that could carry an id, so it is not shown; this is a bug in the reader`            | The provider throttled the reads, and the history reader passed `auditLogThrottled` a limit that could carry an id.                                                                                                                                                             | Wait a minute and run again, or narrow the range with `--since` and `--until`, and report the bug to the provider plugin.           |
| `core.history.reader-error`              | error | `{message}`                                                                                                                                                                             | The history reader threw a plugin or Hardhat error. Its text is shown with key ids, workspace ids and other values that must not print masked, and without the errors it wraps, which are not masked.                                                                           | Follow the message. Run with `--show-ids` to see it unmasked, or with `DEBUG=hardhat:kms:*` to see the step that failed.            |
| `core.history.timed-out`                 | error | `reading the audit log took more than {seconds} seconds, so kms history stopped waiting`                                                                                                | The history reader did not return within the deadline. Long ranges on a slow or throttled log need many requests.                                                                                                                                                               | Narrow the range with `--since` and `--until`, or lower `--limit`.                                                                  |

### Alchemy Wallet APIs

| Id                                 | Kind  | Message                                                                                                                                        | Cause                                                                                                                                                                                                                                                                                      | Fix                                                                                                                                                                                                                                               |
| ---------------------------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `core.alchemy.input`               | error | `checkPreparedCalls: the expected {field} is not valid. Expected {expected}`                                                                   | An argument of `checkPreparedCalls` that describes what you asked for is missing or malformed.                                                                                                                                                                                             | Pass the calls you gave `prepareCalls`, the key's address as `sender`, your chain's id, the delegate you pinned, the account's code from `getCode`, `sponsored: true` only when you passed a policy id, and `maxGasCost` in wei when you did not. |
| `core.alchemy.response-type`       | error | `the prepared calls are {type}; only a user-operation-v070, or an array of one user-operation-v070 and at most one authorization, is accepted` | `prepareCalls` returned another kind of response, such as `paymaster-permit` (ERC-20 gas), a lone `authorization` (undelegation) or an EntryPoint v0.6 user operation. The check cannot rebuild what those ask the key to sign.                                                            | Do not sign it. Prepare plain calls for an EIP-7702 account, with the gas paid by the account or by a policy.                                                                                                                                     |
| `core.alchemy.malformed`           | error | `the prepared {part} has no valid {field}`                                                                                                     | A field of the response is missing or has the wrong type. `checkPreparedCalls` reads the object that `prepareCalls` of `@alchemy/wallet-apis` returns, with bigint quantities and a number chain id, not the raw JSON-RPC response.                                                        | Pass the result of `client.prepareCalls(...)` unchanged. If you did, the response format has changed: do not sign it, and open an issue at https://github.com/aelmanaa/hardhat-kms/issues.                                                        |
| `core.alchemy.signature-request`   | error | `the user operation asks for a {type} signature; only personal_sign over a raw 32-byte hash is accepted`                                       | The signature request is `eth_signTypedData_v4`, another type, or missing. The SDK would sign typed data as given, and the check cannot tie it to your calls.                                                                                                                              | Do not sign it.                                                                                                                                                                                                                                   |
| `core.alchemy.signature-text`      | error | `the user operation asks for personal_sign over a text message, not over a raw 32-byte hash`                                                   | The `personal_sign` request's `data` is a string, or an object without a hex `raw` hash. The check can only tie a raw user operation hash to your calls.                                                                                                                                   | Do not sign it.                                                                                                                                                                                                                                   |
| `core.alchemy.chain`               | error | `the prepared {part} is for chain {returned}, not chain {expected}`                                                                            | The response names another chain than the one you pass. The SDK signs an authorization for the chain the response names.                                                                                                                                                                   | Do not sign it. Check the client's `chain` and the `chainId` you pass to `checkPreparedCalls`.                                                                                                                                                    |
| `core.alchemy.sender`              | error | `the user operation's sender is {returned}, not {expected}`                                                                                    | The user operation would run from another account than the key's address, for example because the client was given an `account`.                                                                                                                                                           | Do not sign it. Pass the key's address as `sender`, and leave the client's `account` unset for an EIP-7702 account.                                                                                                                               |
| `core.alchemy.factory`             | error | `the user operation names a factory; an EIP-7702 account is never deployed by one`                                                             | The user operation has `factory` or `factoryData`. An EIP-7702 account is the key's own address, delegated by an authorization, so its user operations have no factory.                                                                                                                    | Do not sign it.                                                                                                                                                                                                                                   |
| `core.alchemy.hash`                | error | `the hash in the signature request is not the EntryPoint v0.7 hash of the returned user operation on chain {chainId}`                          | The key would sign a hash that does not belong to the user operation in the response, so the calls the check reads are not what the signature authorizes.                                                                                                                                  | Do not sign it, and report it to Alchemy with the time of the call.                                                                                                                                                                               |
| `core.alchemy.calls-function`      | error | `the user operation's callData is not a Modular Account v2 execute or executeBatch call`                                                       | `callData` calls another function of the account, such as `upgradeToAndCall`, a selector the account does not have, or does not decode.                                                                                                                                                    | Do not sign it. Only plain calls are accepted.                                                                                                                                                                                                    |
| `core.alchemy.calls-encoding`      | error | `the user operation's callData is not the standard encoding of its {name} call`                                                                | `callData` decodes, but encoding the decoded call again gives other bytes: it has extra bytes or non-standard offsets.                                                                                                                                                                     | Do not sign it.                                                                                                                                                                                                                                   |
| `core.alchemy.calls-count`         | error | `the user operation makes {returned} calls, and you requested {expected}`                                                                      | The prepared calls add or drop calls.                                                                                                                                                                                                                                                      | Do not sign it. Check that the `calls` you pass to `checkPreparedCalls` are the ones you gave `prepareCalls`.                                                                                                                                     |
| `core.alchemy.calls-differ`        | error | `call {index} of the user operation has another {field} than the call you requested`                                                           | A prepared call goes to another address, sends another value or carries other data than the requested call at the same position. A missing `value` counts as 0 and missing `data` as `0x`.                                                                                                 | Do not sign it. Check that the `calls` you pass to `checkPreparedCalls` are the ones you gave `prepareCalls`, in the same order.                                                                                                                  |
| `core.alchemy.no-paymaster`        | error | `a policy is set, but the user operation names no paymaster, so the account would pay the gas`                                                 | You passed `sponsored: true` for a gas sponsorship policy, and the response has no `paymaster`: the policy id is wrong, its rules refused the user operation, or its budget is spent.                                                                                                      | Check the policy id and its rules in the Alchemy dashboard, or prepare the calls without a policy and pass `sponsored: false` to pay the gas from the account.                                                                                    |
| `core.alchemy.not-sponsored`       | error | `a policy is set, but the response's feePayment says the gas is not sponsored`                                                                 | You passed `sponsored: true` for a gas sponsorship policy, and the response's `feePayment.sponsored` is `false`.                                                                                                                                                                           | Check the policy id and its rules in the Alchemy dashboard, or prepare the calls without a policy and pass `sponsored: false` to pay the gas from the account.                                                                                    |
| `core.alchemy.gas-cost`            | error | `the user operation's maximum gas cost is {cost} wei, which exceeds maxGasCost {max} wei`                                                      | The response's gas limits (call, verification, pre-verification and paymaster) times its `maxFeePerGas` exceed the `maxGasCost` you passed. When no paymaster pays, EntryPoint v0.7 takes that amount from the account up front, and the bundler keeps what the user operation is charged. | Do not sign it. Prepare the calls again when fees are lower, or raise `maxGasCost` if the cost is one you accept.                                                                                                                                 |
| `core.alchemy.auth-nonce`          | error | `the authorization is for nonce {returned}, not the account's nonce {expected}`                                                                | The EIP-7702 authorization in the response names another nonce than the `accountNonce` you passed. Another transaction from the account may have moved the nonce, or the response asks for a delegation that could be applied later.                                                       | Read the account's nonce again just before `prepareCalls`, and prepare the calls again.                                                                                                                                                           |
| `core.alchemy.delegate`            | error | `the authorization delegates the account to {returned}, not to {expected}`                                                                     | The EIP-7702 authorization in the response names another contract than the delegate you pinned. Alchemy may request an authorization to a delegate it recorded for the account without reading the chain.                                                                                  | Do not sign it. If you meant to move to that delegate, change the `delegate` you pass.                                                                                                                                                            |
| `core.alchemy.delegated-elsewhere` | error | `the account is delegated to {current}, not to {expected}`                                                                                     | The account's code is an EIP-7702 delegation to another contract. Signing would run the user operation under that contract, or, with an authorization, re-delegate the account.                                                                                                            | Clear the other delegation first, or change the `delegate` you pass if that contract is the one you trust.                                                                                                                                        |
| `core.alchemy.account-code`        | error | `the account has contract code that is not an EIP-7702 delegation`                                                                             | `accountCode` is neither empty nor `0xef0100` followed by an address, so the address holds a contract, not a key's account.                                                                                                                                                                | Pass the code of the key's own address, read with `getCode` on the chain you send on.                                                                                                                                                             |
| `core.alchemy.not-delegated`       | error | `the account has no delegation, and the response has no authorization`                                                                         | The key's address has no code, so the user operation cannot run as a smart account without an authorization, and the response has none.                                                                                                                                                    | Read the account's code again just before `prepareCalls`, then prepare the calls again.                                                                                                                                                           |

### Internal

| Id                                  | Kind     | Message                                                     | Cause                                                                                                                   | Fix                                                                                                         |
| ----------------------------------- | -------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `core.internal.identifier-part`     | internal | `an identifier part has no value`                           | Joining the parts of a key id found a part without a value. Every part always has one.                                  | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.       |
| `core.internal.wrong-provider`      | internal | `Expected a "{expected}" key, got "{actual}"`               | A provider's config resolver was given another provider's key. Validation dispatches on `provider`, so this is a guard. | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.       |
| `core.internal.unvalidated-key`     | internal | `Unknown key "{account}" in networks.{network}.kmsAccounts` | Config resolution met a key name that validation would have refused, so the config was not validated first.             | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.       |
| `core.internal.kms-option-no-value` | internal | `no value for {name}`                                       | A `--kms` key asked for a variable the option had not read. It only asks for the ones it read.                          | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.       |
| `core.internal.no-package-version`  | internal | `{packageName}/package.json has no version`                 | An installed package's package.json has no `version`, so the install is broken.                                         | Reinstall the dependencies. If it repeats, open an issue at https://github.com/aelmanaa/hardhat-kms/issues. |

## @hardhat-kms/aws

### Keys

| Id                          | Kind  | Message                                                                                                                              | Cause                                                                                                                                                                            | Fix                                                                                                              |
| --------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `aws.key.spec`              | error | `the key spec is {keySpec}, not ECC_SECG_P256K1 (secp256k1). Create the key with --key-spec ECC_SECG_P256K1 --key-usage SIGN_VERIFY` | The key is not a secp256k1 key, for example an RSA or a P-256 key.                                                                                                               | A key's spec cannot be changed. Create a new key with the command the message gives, and point the config at it. |
| `aws.key.usage`             | error | `the key usage is {keyUsage}, not SIGN_VERIFY`                                                                                       | The key was created for another usage, such as `ENCRYPT_DECRYPT` or `GENERATE_VERIFY_MAC`.                                                                                       | A key's usage cannot be changed. Create a new key with `--key-usage SIGN_VERIFY`.                                |
| `aws.key.signing-algorithm` | error | `the key does not support ECDSA_SHA_256`                                                                                             | The `GetPublicKey` answer does not list `ECDSA_SHA_256` among the key's signing algorithms. Every `ECC_SECG_P256K1` signing key supports it, so the endpoint may not be AWS KMS. | Check the key's `endpoint`, if one is set. Against AWS KMS itself, report it.                                    |
| `aws.key.no-key-arn`        | error | `the response has no key ARN`                                                                                                        | The `GetPublicKey` answer has no key ARN, which the adapter needs: it signs with the ARN, never with an alias.                                                                   | Check the key's `endpoint`, if one is set. Against AWS KMS itself, report it.                                    |
| `aws.key.no-public-key`     | error | `the response has no public key`                                                                                                     | The `GetPublicKey` answer has no public key.                                                                                                                                     | Check the key's `endpoint`, if one is set. Against AWS KMS itself, report it.                                    |

### Signing

| Id                            | Kind  | Message                                                              | Cause                                                                                                                         | Fix                                                                           |
| ----------------------------- | ----- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `aws.sign.lookup-unfinished`  | error | `the key lookup did not finish, so there is no key ARN to sign with` | The `GetPublicKey` call that learns the key ARN was abandoned when its time ran out. The adapter never signs without the ARN. | Run again. If it repeats, check the network and region, or raise `timeoutMs`. |
| `aws.sign.response-key`       | error | `the response is for another key than the one requested`             | The `Sign` answer names another key ARN than the one the adapter signed with. The signature is refused.                       | Check the key's `endpoint` and any proxy. Against AWS KMS itself, report it.  |
| `aws.sign.response-algorithm` | error | `the response does not use ECDSA_SHA_256`                            | The `Sign` answer names another signing algorithm than `ECDSA_SHA_256`. The signature is refused.                             | Check the key's `endpoint` and any proxy. Against AWS KMS itself, report it.  |
| `aws.sign.no-signature`       | error | `the response has no signature`                                      | The `Sign` answer has no signature.                                                                                           | Check the key's `endpoint` and any proxy. Against AWS KMS itself, report it.  |

### Connecting

| Id                      | Kind  | Message                                                                                                                                           | Cause                                                                                                           | Fix                                                                                                                  |
| ----------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `aws.connect.no-region` | error | ``no AWS region is configured. Set `region` on the key, `kms.defaults.aws.region`, AWS_REGION, or a region in the AWS profile, or use a key ARN`` | The AWS SDK found no region for the key: the key id is not an ARN, and no region is set anywhere the SDK looks. | Set `region` on the key or `kms.defaults.aws.region`, set `AWS_REGION`, give the profile a region, or use a key ARN. |

### History

| Id                              | Kind  | Message                                                                                                                                                                          | Cause                                                                                                                                                                                                                        | Fix                                                                                                                                         |
| ------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `aws.history.key-lookup-denied` | error | `cannot find the key ARN: the credentials lack kms:GetPublicKey, which kms history needs for a key named by an alias or a bare key id. Grant it, or name the key by its key ARN` | CloudTrail records each sign event under the key ARN. For a key named by an alias or a bare key id, `kms history` first calls `GetPublicKey` to learn the ARN, and AWS KMS refused that call.                                | Grant `kms:GetPublicKey` on the key to the identity that runs `kms history` (signing needs it too), or set `keyId` to the key ARN.          |
| `aws.history.unreadable-event`  | error | `CloudTrail returned a sign event that is not a readable event record, so the history cannot be shown in full`                                                                   | A `LookupEvents` answer held a `Sign` event whose `CloudTrailEvent` field is not a JSON object with a valid `eventTime`. The reader cannot tell whether the event belongs to the key, so it stops instead of leaving it out. | Run again. If it repeats, look at the event in the CloudTrail console, and open an issue at https://github.com/aelmanaa/hardhat-kms/issues. |

### Internal

| Id                                | Kind     | Message                                     | Cause                                                                                          | Fix                                                                                                         |
| --------------------------------- | -------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `aws.internal.no-package-version` | internal | `{packageName}/package.json has no version` | The installed @hardhat-kms/aws has no `version` in its package.json, so the install is broken. | Reinstall the dependencies. If it repeats, open an issue at https://github.com/aelmanaa/hardhat-kms/issues. |

## @hardhat-kms/azure

### Credentials

| Id                                          | Kind   | Message                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Cause                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Fix                                                                                                                                   |
| ------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `azure.credential.none`                     | error  | ``no Azure credential returned a token ({errorName}). Run `az login`, or set AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET for a service principal``                                                                                                                                                                                                                                                                                         | No credential source of the chain is configured: no service principal, workload identity, managed identity or `az login`.                                                                                                                                                                                                                                                                                                                                                               | Run `az login`, or set the variables of a service principal or workload identity, as the setup guide describes.                       |
| `azure.credential.failed`                   | error  | `a configured Azure credential could not sign in ({errorName}). Check the service principal (AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET or AZURE_CLIENT_CERTIFICATE_PATH), the workload identity or the managed identity; unset the variables of a source you do not mean to use`                                                                                                                                                        | A credential source is configured but its sign-in failed, for example a wrong or expired `AZURE_CLIENT_SECRET` or a wrong `AZURE_TENANT_ID`. The chain does not fall through to `az login` after this.                                                                                                                                                                                                                                                                                  | Fix that source's settings, or unset the variables of a source you do not mean to use.                                                |
| `azure.credential.username-password`        | error  | ``AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_USERNAME and AZURE_PASSWORD are set, with no client secret or certificate, which selects username and password sign-in. hardhat-kms refuses it, because that sign-in cannot do multifactor authentication. Set AZURE_CLIENT_SECRET or AZURE_CLIENT_CERTIFICATE_PATH for a service principal, or unset AZURE_USERNAME and AZURE_PASSWORD to sign in with `az login`, workload identity or a managed identity`` | With these four variables set and no secret or certificate, @azure/identity's environment credential would sign in as the user with the password alone (OAuth resource owner password credentials). That sign-in cannot do multifactor authentication, and Microsoft has deprecated it. The plugin refuses before it asks any source for a token, even when `az login`, workload identity or a managed identity would have worked. The message names the variables, never their values. | Unset `AZURE_USERNAME` and `AZURE_PASSWORD`, or set `AZURE_CLIENT_SECRET` or `AZURE_CLIENT_CERTIFICATE_PATH` for a service principal. |
| `azure.credential.tenant-id`                | error  | `AZURE_TENANT_ID is not a tenant id: it may hold only letters, digits, hyphens (-) and dots (.)`                                                                                                                                                                                                                                                                                                                                                        | The variable holds another character, such as a space or a slash. @azure/identity refuses such a tenant, so the plugin checks it when it builds the credential chain, before any request. The message never shows the value.                                                                                                                                                                                                                                                            | Set `AZURE_TENANT_ID` to the directory (tenant) id that `az account show --query tenantId -o tsv` prints, or unset it.                |
| `azure.credential.environment-failed`       | reason | `the service principal from the environment could not sign in`                                                                                                                                                                                                                                                                                                                                                                                          | The service principal that `AZURE_CLIENT_SECRET` or `AZURE_CLIENT_CERTIFICATE_PATH` selects did not get a token, for any reason, such as a wrong secret, an unreadable certificate or a vault in a tenant that `AZURE_ADDITIONALLY_ALLOWED_TENANTS` does not allow. The error is named `AuthenticationError`, so the chain stops there and does not fall through to `az login`, and the plugin reports `azure.credential.failed`.                                                       | See `azure.credential.failed`.                                                                                                        |
| `azure.credential.aborted`                  | reason | `The operation was aborted.`                                                                                                                                                                                                                                                                                                                                                                                                                            | A token request was abandoned when the call's time ran out. The error is named `AbortError`, as the Azure SDK names its own; the plugin reports the call as `no answer within … ms`.                                                                                                                                                                                                                                                                                                    | See `core.signer.no-answer`.                                                                                                          |
| `azure.credential.managed-identity-timeout` | reason | `ManagedIdentityCredential: no token within {seconds} s`                                                                                                                                                                                                                                                                                                                                                                                                | The managed identity endpoint gave no token in time, which happens outside Azure when the endpoint accepts a connection and never answers. The managed identity is the last source of the credential chain, so the chain then fails, and the plugin reports `azure.credential.none` with the chain's class name. This text is the message of that source's `CredentialUnavailableError`.                                                                                                | Outside Azure, sign in with `az login` or a service principal. On Azure, check that the managed identity is assigned to the resource. |

### Key Vault answers

| Id                               | Kind  | Message                                                                                                                                                                                                                                                                                                                                                                                                                                                       | Cause                                                                                                                                                                                       | Fix                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| -------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `azure.service.unreachable`      | error | `Key Vault could not be reached. Check the vault URL, the network and any proxy`                                                                                                                                                                                                                                                                                                                                                                              | The request got no HTTP answer.                                                                                                                                                             | Check the vault URL, DNS, the network and any proxy.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `azure.service.unreachable-code` | error | `Key Vault could not be reached ({code}). Check the vault URL, the network and any proxy`                                                                                                                                                                                                                                                                                                                                                                     | The request got no HTTP answer. The code says why, for example `ENOTFOUND` for DNS.                                                                                                         | Check the vault URL, DNS, the network and any proxy.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `azure.service.401`              | error | `Key Vault answered {status}: the credential was not accepted`                                                                                                                                                                                                                                                                                                                                                                                                | The token is for another tenant, or has expired.                                                                                                                                            | Run `az login` again, or check `AZURE_TENANT_ID`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `azure.service.403`              | error | ``Key Vault answered {status}: the identity may not use this key. It needs to read the key and sign with it: on an RBAC vault, a role with `Microsoft.KeyVault/vaults/keys/read` and `Microsoft.KeyVault/vaults/keys/sign/action` on the key, such as a custom role or the built-in Key Vault Crypto User; in an access policy, the `get` and `sign` key permissions. See step 2 of the Azure setup guide. A disabled key or a firewall rule also gives 403`` | The identity may not read the key or sign with it, the role assignment has not taken effect yet (it can take a few minutes), the key is disabled, or the vault firewall blocks the network. | Grant read and sign on the key, as step 2 of the Azure setup guide shows: on an RBAC vault, a custom role with the data actions `Microsoft.KeyVault/vaults/keys/read` and `Microsoft.KeyVault/vaults/keys/sign/action`, assigned on the key, or the built-in Key Vault Crypto User role, which also holds actions the plugin does not use; in an access policy, the `get` and `sign` key permissions; on a Managed HSM, a local role with `Microsoft.KeyVault/managedHsm/keys/read/action` and `Microsoft.KeyVault/managedHsm/keys/sign/action`. Then wait a few minutes, and check that the key is enabled and the vault's network rules. |
| `azure.service.404`              | error | `Key Vault answered {status}: the key or key version does not exist in this vault. Check the key id`                                                                                                                                                                                                                                                                                                                                                          | The vault has no key with this name or version.                                                                                                                                             | Check `keyId`, or `keyName` and `keyVersion`. A deleted key must be recovered first.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `azure.service.other`            | error | `Key Vault answered {status}`                                                                                                                                                                                                                                                                                                                                                                                                                                 | Key Vault answered with another HTTP status. Only the status and Key Vault's error code are shown, since the service's message names the vault, the key and the caller.                     | Look the status and code up in the Key Vault documentation, and run with `DEBUG=hardhat:kms:*` to see the call.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |

### Responses

| Id                               | Kind  | Message                                                  | Cause                                                                                        | Fix                                                          |
| -------------------------------- | ----- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `azure.response.key-version`     | error | `the response is for another key version`                | Key Vault returned another version than the one configured or pinned.                        | Check that `keyId` names the version you mean.               |
| `azure.response.no-public-key`   | error | `the response has no public key`                         | The key read from Key Vault has no JSON Web Key.                                             | Run again; if it repeats, report it.                         |
| `azure.response.no-versioned-id` | error | `the response has no versioned key id`                   | A Key Vault answer has no key id with a version, which the adapter needs to pin the version. | Run again; if it repeats, report it.                         |
| `azure.response.key`             | error | `the response is for another key than the one requested` | A Key Vault answer names another vault or key than the configured one. It is refused.        | Check the vault URL and any proxy; if it repeats, report it. |
| `azure.response.no-signature`    | error | `the response has no signature`                          | The sign answer has no signature.                                                            | Run again; if it repeats, report it.                         |

### Keys

| Id                            | Kind  | Message                                                                                                                                                                                      | Cause                                                                                                         | Fix                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ----------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `azure.key.type`              | error | `the key type is {keyType}, not EC or EC-HSM. Create an EC key on the P-256K curve`                                                                                                          | The key is not an elliptic-curve key, for example an RSA key.                                                 | A key's type cannot be changed. Create a new key with `--kty EC --curve P-256K`, as in the setup guide.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `azure.key.curve`             | error | `the key curve is {curve}, not P-256K (secp256k1). Create the key with --kty EC --curve P-256K`                                                                                              | The key is an EC key on another curve, such as P-256.                                                         | A key's curve cannot be changed. Create a new key with the command the message gives.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `azure.key.disabled`          | error | `` the key version is disabled. Enable it with `az keyvault key set-attributes {vaultOption} {vaultName} --name {keyName} --version {keyVersion} --enabled true` ``                          | The key version is disabled.                                                                                  | Run the command the message gives. It names the vault (`--vault-name`, or `--hsm-name` for a Managed HSM), the key and the version, because without `--version` the command changes the latest version, which may not be the one the config signs with. A part of the key id that comes from a configuration variable is shown as `<vault-name>`, `<key-name>` or `<version>`; fill it in from that variable. Run it as an identity with the keys/update permission, such as a key administrator with Key Vault Crypto Officer, or Managed HSM Crypto Officer on a Managed HSM: the two-action signing role cannot. `--vault-name` and `--hsm-name` build the vault URL from the cloud `az` is set to, so for a vault in another Azure cloud, run `az cloud set` first. |
| `azure.key.not-yet-valid`     | error | `the key version is not valid before {date}`                                                                                                                                                 | The key's activation date is in the future.                                                                   | Change it with `az keyvault key set-attributes --vault-name <vault-name> --name <key-name> --version <version> --not-before <date>` (or `--hsm-name` for a Managed HSM), or use another version. Without `--version` the command changes the latest version. Run it as an identity with the keys/update permission, such as a key administrator with Key Vault Crypto Officer, or Managed HSM Crypto Officer on a Managed HSM: the two-action signing role cannot. `--vault-name` and `--hsm-name` build the vault URL from the cloud `az` is set to, so for a vault in another Azure cloud, run `az cloud set` first.                                                                                                                                                  |
| `azure.key.expired`           | error | `the key version expired at {date}`                                                                                                                                                          | The key's expiry date has passed. The plugin checks it when it reads the key and again before each signature. | Change it with `az keyvault key set-attributes --vault-name <vault-name> --name <key-name> --version <version> --expires <date>` (or `--hsm-name` for a Managed HSM), or use another version. Without `--version` the command changes the latest version. Run it as an identity with the keys/update permission, such as a key administrator with Key Vault Crypto Officer, or Managed HSM Crypto Officer on a Managed HSM: the two-action signing role cannot. `--vault-name` and `--hsm-name` build the vault URL from the cloud `az` is set to, so for a vault in another Azure cloud, run `az cloud set` first.                                                                                                                                                     |
| `azure.key.no-sign-operation` | error | `` the key's permitted operations do not include sign. Set them with `az keyvault key set-attributes {vaultOption} {vaultName} --name {keyName} --version {keyVersion} --ops sign verify` `` | The key was created without `sign` in `--ops`.                                                                | Run the command the message gives. It names the vault (`--vault-name`, or `--hsm-name` for a Managed HSM), the key and the version, because without `--version` the command changes the latest version. A part of the key id that comes from a configuration variable is shown as `<vault-name>`, `<key-name>` or `<version>`; fill it in from that variable. Run it as an identity with the keys/update permission, such as a key administrator with Key Vault Crypto Officer, or Managed HSM Crypto Officer on a Managed HSM: the two-action signing role cannot. `--vault-name` and `--hsm-name` build the vault URL from the cloud `az` is set to, so for a vault in another Azure cloud, run `az cloud set` first.                                                 |
| `azure.key.not-key-url`       | error | `the key id is not an Azure Key Vault key URL`                                                                                                                                               | The key id is not a Key Vault key URL. The config checks refuse such values first, so this is a guard.        | Open an issue at https://github.com/aelmanaa/hardhat-kms/issues with the message and the stack trace.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

### Signing

| Id                             | Kind  | Message                                                                  | Cause                                                                                                                     | Fix                                                                |
| ------------------------------ | ----- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `azure.sign.lookup-unfinished` | error | `the key lookup did not finish, so there is no key version to sign with` | The key read that pins the version was abandoned when its time ran out. The adapter never signs without a pinned version. | Run again. If it repeats, check the network, or raise `timeoutMs`. |
| `azure.sign.signature-version` | error | `the signature is from another key version than the pinned one`          | The sign answer's `kid` names another version than the pinned one. The signature is refused.                              | Report it if it happens against Key Vault itself.                  |

### History

| Id                                  | Kind  | Message                                                                                                                                                                                                                                                                           | Cause                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Fix                                                                                                                                                                                                                                                                            |
| ----------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `azure.history.no-workspace`        | error | `` `kms history` reads Azure Key Vault's audit log from a Log Analytics workspace, and kms.audit.azure.workspaceId is not set. Set it to the workspace id (a GUID) that the vault's diagnostic setting sends AuditEvent logs to ``                                                | Key Vault keeps no audit log of its own: a diagnostic setting on the vault sends it to a Log Analytics workspace, and the plugin needs to know which one.                                                                                                                                                                                                                                                                                                                | Set `kms.audit.azure.workspaceId` to the workspace id, as the Azure setup guide's "Audit logs" section describes. `az monitor log-analytics workspace show --query customerId` prints it.                                                                                      |
| `azure.history.workspace-id`        | error | `kms.audit.azure.workspaceId is not a GUID, so no Log Analytics query is sent to it`                                                                                                                                                                                              | The reader puts the workspace id in the query URL, so it accepts a GUID only. The config check refuses other values first, so this means a value reached the reader without it.                                                                                                                                                                                                                                                                                          | Set `kms.audit.azure.workspaceId` to the workspace id (`customerId`), not its name or resource id.                                                                                                                                                                             |
| `azure.history.key-id`              | error | `the key id is not a Key Vault key URL with a host of letters, digits, . and - and a key name of letters, digits and -, so no Log Analytics query is built from it`                                                                                                               | `kms history` builds its query only from the checked host and key name of the key URL, so that no part can change the query. The config check refuses other values first, so this means a key reached the reader without it.                                                                                                                                                                                                                                             | Check `keyId`, or `vaultUrl` and `keyName`.                                                                                                                                                                                                                                    |
| `azure.history.managed-hsm`         | error | `` `kms history` does not support Managed HSM keys yet ``                                                                                                                                                                                                                         | The reader queries the `AZKVAuditLogs` table of Key Vault audit events. Reading the audit log of a Managed HSM is not supported yet.                                                                                                                                                                                                                                                                                                                                     | Read the Managed HSM audit log in the Azure portal or with `az monitor log-analytics query`, or open an issue asking for Managed HSM support.                                                                                                                                  |
| `azure.history.sovereign-cloud`     | error | `` `kms history` reads only vaults in Azure's public cloud (vault.azure.net) for now, since other clouds use another Log Analytics endpoint ``                                                                                                                                    | Azure China and Azure Government answer Log Analytics queries on their own endpoints, which the plugin does not call yet.                                                                                                                                                                                                                                                                                                                                                | Query `AZKVAuditLogs` with `az monitor log-analytics query` in that cloud, or open an issue asking for it.                                                                                                                                                                     |
| `azure.history.no-table`            | error | `the Log Analytics workspace has no AZKVAuditLogs table that this identity may read: no diagnostic setting sends Key Vault audit events to it in resource-specific mode, or the identity may not be allowed to read this table. See the Azure setup guide's "Audit logs" section` | The `AZKVAuditLogs` table appears once a vault's diagnostic setting sends the `AuditEvent` category to the workspace with the resource-specific destination. A setting in the older Azure diagnostics mode writes to `AzureDiagnostics`, which the plugin does not read, and a setting that sends to a storage account or an event hub writes nothing here. An identity whose access is limited to other tables of the workspace may also be unable to resolve this one. | Create the diagnostic setting with `--export-to-resource-specific true`, check that `kms.audit.azure.workspaceId` names the workspace it sends to, or give the identity read access to the `AZKVAuditLogs` table, such as the Log Analytics Data Reader role on the workspace. |
| `azure.history.workspace-not-found` | error | `Log Analytics found no workspace with the id in kms.audit.azure.workspaceId (404 WorkspaceNotFoundError)`                                                                                                                                                                        | No workspace has this id, or the id is the workspace's resource id or name instead of its workspace id.                                                                                                                                                                                                                                                                                                                                                                  | Set `kms.audit.azure.workspaceId` to the workspace's `customerId`, which `az monitor log-analytics workspace show` prints.                                                                                                                                                     |
| `azure.history.401`                 | error | `Log Analytics answered {status}: the credential was not accepted`                                                                                                                                                                                                                | The token is for another tenant than the workspace's, or has expired.                                                                                                                                                                                                                                                                                                                                                                                                    | Run `az login` again, or check `AZURE_TENANT_ID`.                                                                                                                                                                                                                              |
| `azure.history.read-failed`         | error | `the Log Analytics query failed ({status})`                                                                                                                                                                                                                                       | Log Analytics answered the query with an error. Only the HTTP status and the service's error codes are shown, since its message can name the workspace and the vault.                                                                                                                                                                                                                                                                                                    | For a 5xx status, try again later. Run with `DEBUG=hardhat:kms:*` to see the call, and report a 400 with the codes it names.                                                                                                                                                   |
| `azure.history.partial`             | error | `Log Analytics returned part of the result with an error ({code}), so the history would be incomplete`                                                                                                                                                                            | A query can succeed with only part of its result, for example when it hits a limit of the service. The reader fails rather than show part of the history as if it were all of it.                                                                                                                                                                                                                                                                                        | Narrow the range with `--since` and `--until`, or lower `--limit`, and run again.                                                                                                                                                                                              |
| `azure.history.unreachable`         | error | `could not reach Log Analytics ({code}). Check the network connection, DNS and any proxy`                                                                                                                                                                                         | The query got no HTTP answer, after the Azure SDK's retries. The code says why, for example `ENOTFOUND` for DNS.                                                                                                                                                                                                                                                                                                                                                         | Check that `api.loganalytics.azure.com` can be reached, and any `HTTPS_PROXY`.                                                                                                                                                                                                 |
| `azure.history.bad-response`        | error | `Log Analytics answered in a form this plugin does not read: {problem}`                                                                                                                                                                                                           | The query answer, or a `KeySign` row in it, lacks a field such an answer always has. The reader fails rather than show part of the history as if it were all of it.                                                                                                                                                                                                                                                                                                      | Run again; if it repeats, report it with the problem the message names.                                                                                                                                                                                                        |

### Internal

| Id                                  | Kind     | Message                                     | Cause                                                                                            | Fix                                                                                                         |
| ----------------------------------- | -------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `azure.internal.no-package-version` | internal | `{packageName}/package.json has no version` | The installed @hardhat-kms/azure has no `version` in its package.json, so the install is broken. | Reinstall the dependencies. If it repeats, open an issue at https://github.com/aelmanaa/hardhat-kms/issues. |

## @hardhat-kms/gcp

### Responses

| Id                           | Kind  | Message                                                          | Cause                                                                                               | Fix                                  |
| ---------------------------- | ----- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------ |
| `gcp.response.key-version`   | error | `the response is for another key version than the one requested` | Cloud KMS answered for another key version than the one requested. The adapter does not retry this. | Run again; if it repeats, report it. |
| `gcp.response.no-public-key` | error | `the response has no public key`                                 | The `getPublicKey` answer has no PEM public key.                                                    | Run again; if it repeats, report it. |
| `gcp.response.no-signature`  | error | `the response has no signature`                                  | The `asymmetricSign` answer has no signature.                                                       | Run again; if it repeats, report it. |

### Keys

| Id                  | Kind  | Message                                                                                                                                                                                                      | Cause                                           | Fix                                                                                                                   |
| ------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `gcp.key.algorithm` | error | `the key version's algorithm is {algorithm}, not EC_SIGN_SECP256K1_SHA256 (secp256k1). Create the key with --purpose asymmetric-signing --default-algorithm ec-sign-secp256k1-sha256 --protection-level hsm` | The key version is not a secp256k1 signing key. | A key's algorithm cannot be changed. Create a new key with the command the message gives, and point the config at it. |

### Signing

| Id                           | Kind  | Message                                                                        | Cause                                                                                                                                           | Fix                                                                |
| ---------------------------- | ----- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `gcp.sign.lookup-unfinished` | error | `the key lookup did not finish, so the key version's algorithm is not checked` | The `getPublicKey` call that checks the key version's algorithm was abandoned when its time ran out. The adapter never signs before that check. | Run again. If it repeats, check the network, or raise `timeoutMs`. |

### Retries

| Id                                   | Kind   | Message                                                                                                  | Cause                                                                                                                                          | Fix                                                                                                    |
| ------------------------------------ | ------ | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `gcp.retry.checksum`                 | error  | `{reason}, after {attempts} attempts. Data is being corrupted between this machine and Google Cloud KMS` | A CRC32C checksum failed on every attempt. The reason is one of the checksum reasons below.                                                    | Check proxies or other software that rewrites HTTPS traffic between this machine and Cloud KMS.        |
| `gcp.retry.unavailable`              | error  | `{reason}, after {attempts} attempts. Check the network connection, DNS and any proxy`                   | Cloud KMS could not be reached, or answered UNAVAILABLE, on every attempt. The reason is `gcp.reason.unreachable` or `gcp.reason.unavailable`. | Check the network, DNS and any `HTTPS_PROXY`. For UNAVAILABLE without a network code, try again later. |
| `gcp.retry.abandoned`                | error  | `{reason}`                                                                                               | A call failed in a way a retry could fix, but its time had run out, so it was not repeated. The message is one of the reasons below.           | Run again, or raise `timeoutMs`.                                                                       |
| `gcp.reason.pem-checksum`            | reason | `the public key does not match its checksum (pemCrc32c)`                                                 | The public key was corrupted on its way from Cloud KMS.                                                                                        | See `gcp.retry.checksum`.                                                                              |
| `gcp.reason.digest-not-confirmed`    | reason | `Google Cloud KMS did not confirm the digest's checksum (verifiedDigestCrc32c)`                          | The checksum sent with the digest did not reach Cloud KMS. The adapter never signs on without it.                                              | See `gcp.retry.checksum`.                                                                              |
| `gcp.reason.signature-checksum`      | reason | `the signature does not match its checksum (signatureCrc32c)`                                            | The signature was corrupted on its way from Cloud KMS.                                                                                         | See `gcp.retry.checksum`.                                                                              |
| `gcp.reason.digest-checksum-refused` | reason | `Google Cloud KMS refused the digest's checksum (digestCrc32c, INVALID_ARGUMENT)`                        | The digest was corrupted on its way to Cloud KMS, which refused it.                                                                            | See `gcp.retry.checksum`.                                                                              |
| `gcp.reason.unavailable`             | reason | `Google Cloud KMS is unavailable (UNAVAILABLE)`                                                          | Cloud KMS answered that it is unavailable.                                                                                                     | Try again later.                                                                                       |
| `gcp.reason.unreachable`             | reason | `could not reach Google Cloud KMS ({code})`                                                              | The request never reached Cloud KMS. The code says why: `ENOTFOUND` or `EAI_AGAIN` for DNS, `ECONNREFUSED` or `ECONNRESET` for the connection. | Check the network, DNS and any `HTTPS_PROXY`.                                                          |

### Google Cloud KMS answers

| Id                               | Kind  | Message                                                                                                                                                                                                                              | Cause                                                                                                                                       | Fix                                                                                                                                       |
| -------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `gcp.status.not-found`           | error | `the key version was not found (NOT_FOUND). Check the project, location, key ring, key and version`                                                                                                                                  | The project, location, key ring, key or version does not exist, or the caller cannot see it.                                                | Check `keyVersionName` or its parts.                                                                                                      |
| `gcp.status.permission-denied`   | error | `permission denied (PERMISSION_DENIED). The caller needs cloudkms.cryptoKeyVersions.viewPublicKey and cloudkms.cryptoKeyVersions.useToSign on the key, for example through roles/cloudkms.signer and roles/cloudkms.publicKeyViewer` | The identity lacks `viewPublicKey` or `useToSign` on this key.                                                                              | Grant the roles the message names on the key, as in the setup guide.                                                                      |
| `gcp.status.failed-precondition` | error | `the key version cannot be used (FAILED_PRECONDITION). It may be disabled, destroyed or scheduled for destruction; enable it or configure another version`                                                                           | The key version is disabled, scheduled for destruction or destroyed.                                                                        | Enable it with `gcloud kms keys versions enable`, restore it first with `gcloud kms keys versions restore`, or configure another version. |
| `gcp.status.unauthenticated`     | error | ``the Google Cloud credentials were refused (UNAUTHENTICATED). Run `gcloud auth application-default login` again, or check GOOGLE_APPLICATION_CREDENTIALS``                                                                          | The credentials expired or were revoked: Cloud KMS or Cloud Logging refused them, or the OAuth token endpoint refused to refresh the login. | Run `gcloud auth application-default login` again, or check the file `GOOGLE_APPLICATION_CREDENTIALS` names.                              |
| `gcp.status.resource-exhausted`  | error | `Google Cloud KMS is throttling requests (RESOURCE_EXHAUSTED). Try again later, or raise the project's Cloud KMS quota`                                                                                                              | The project hit its Cloud KMS quota.                                                                                                        | Try again later, or ask for a higher quota.                                                                                               |
| `gcp.status.deadline-exceeded`   | error | `Google Cloud KMS did not answer in time (DEADLINE_EXCEEDED)`                                                                                                                                                                        | The request reached its deadline, the key's `timeoutMs`, as the SDK reports it.                                                             | Check the network, or raise `timeoutMs`.                                                                                                  |
| `gcp.status.other`               | error | `the Google Cloud KMS call failed ({status})`                                                                                                                                                                                        | Cloud KMS answered with another gRPC status. Only the status name is shown, since the server's message names the project and the key.       | Look the status up in the Cloud KMS documentation, and run with `DEBUG=hardhat:kms:*` to see the call.                                    |

### Connecting

| Id                             | Kind  | Message                                                                                                                                                                                                                             | Cause                                                                                                                                                                                                                                                                                                                               | Fix                                                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gcp.connect.no-credentials`   | error | ``no Google Cloud credentials found. Run `gcloud auth application-default login`, or set GOOGLE_APPLICATION_CREDENTIALS``                                                                                                           | google-auth-library found no Application Default Credentials.                                                                                                                                                                                                                                                                       | Run `gcloud auth application-default login`, or set `GOOGLE_APPLICATION_CREDENTIALS` to a credentials file.                                                                                                                                                                                                                                                                                                    |
| `gcp.connect.credentials-file` | error | `` the credentials file GOOGLE_APPLICATION_CREDENTIALS names could not be read. Check that it exists and holds Google Cloud credentials, or unset GOOGLE_APPLICATION_CREDENTIALS and run `gcloud auth application-default login` `` | google-auth-library could not load the file `GOOGLE_APPLICATION_CREDENTIALS` points at: it does not exist, is not a file, or does not hold credentials it can parse. The message leaves out the path.                                                                                                                               | Point `GOOGLE_APPLICATION_CREDENTIALS` at a credentials file, or unset it and run `gcloud auth application-default login`.                                                                                                                                                                                                                                                                                     |
| `gcp.connect.token-exchange`   | error | `the token exchange refused the external credentials ({code}). Check the workload identity pool provider's audience and attribute condition, and that the external token has not expired`                                           | With workload identity federation, google-auth-library swaps the external token, such as a GitHub Actions OIDC token, for a Google Cloud access token at the Security Token Service, which refused it. Only the OAuth error code is shown: the error's description can repeat claims from the token.                                | For `invalid_grant`, check that the provider's audience matches the credentials file, that the attribute condition accepts the token's claims, and that the token is current. For `invalid_request` or `unauthorized_client`, recreate the credentials file from the provider.                                                                                                                                 |
| `gcp.connect.auth-endpoint`    | error | `getting a Google Cloud access token failed: {endpoint} answered HTTP {status}. See gcp.connect.auth-endpoint in the errors reference`                                                                                              | While getting an access token, google-auth-library called a Google endpoint other than Cloud KMS or Cloud Logging, and that endpoint refused the call with a 4xx status. Only the HTTP status and the endpoint's name are shown: the request path can hold the project number. A 5xx, 408 or 429 is retried and reported as before. | For the token exchange, check the workload identity pool provider and the credentials file. For service account impersonation, grant the federated identity `roles/iam.workloadIdentityUser` on the service account. The plugin passes the key's project, so the project lookup should not happen; if it does, set `GOOGLE_CLOUD_PROJECT` and open an issue at https://github.com/aelmanaa/hardhat-kms/issues. |

### History

| Id                           | Kind  | Message                                                                                                                                                               | Cause                                                                                                                                                                                                                                | Fix                                                                                                                                                |
| ---------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gcp.history.key-name`       | error | `the key version name does not split into a project, location, key ring, key and version of letters, digits, _ . : and -, so no Cloud Logging query is built from it` | `kms history` builds its Cloud Logging filter only from the checked parts of a key version name, so that no part can change the query. The config check refuses such names first, so this means a key reached the reader without it. | Check `keyVersionName` or its parts.                                                                                                               |
| `gcp.history.api-disabled`   | error | `the Cloud Logging API is disabled in the project the request is billed to (SERVICE_DISABLED). Enable logging.googleapis.com there, or use another quota project`     | Cloud Logging refused the read because its API is not enabled in the quota project of the credentials.                                                                                                                               | Run `gcloud services enable logging.googleapis.com` in that project, or pick another one with `gcloud auth application-default set-quota-project`. |
| `gcp.history.read-failed`    | error | `reading the Cloud Logging entries failed ({status})`                                                                                                                 | Cloud Logging answered `entries.list` with an error. Only the HTTP status and its status name are shown, since the server's message can name the project.                                                                            | For `404 NOT_FOUND`, check the project in the key's name. For a 5xx status, try again later. Run with `DEBUG=hardhat:kms:*` to see the call.       |
| `gcp.history.unreachable`    | error | `could not reach Cloud Logging ({code}), after {attempts} attempts. Check the network connection, DNS and any proxy`                                                  | The request never reached Cloud Logging. The code says why: `ENOTFOUND` or `EAI_AGAIN` for DNS, `ECONNREFUSED` or `ECONNRESET` for the connection.                                                                                   | Check the network, DNS and any `HTTPS_PROXY`.                                                                                                      |
| `gcp.history.call-timed-out` | error | `Cloud Logging did not answer within {seconds} seconds, after {attempts} attempts`                                                                                    | Each `entries.list` call has 30 seconds, and one that gets no answer in time is retried once. A long range over many entries, or a slow network, can take longer.                                                                    | Narrow the range with `--since` and `--until`, or check the network.                                                                               |
| `gcp.history.bad-response`   | error | `Cloud Logging answered in a form this plugin does not read: {problem}`                                                                                               | The `entries.list` answer, or an `AsymmetricSign` entry in it, lacks a field such an answer always has. The reader fails rather than show part of the history as if it were all of it.                                               | Run again; if it repeats, report it with the problem the message names.                                                                            |

### Internal

| Id                                | Kind     | Message                                     | Cause                                                                                          | Fix                                                                                                         |
| --------------------------------- | -------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `gcp.internal.no-package-version` | internal | `{packageName}/package.json has no version` | The installed @hardhat-kms/gcp has no `version` in its package.json, so the install is broken. | Reinstall the dependencies. If it repeats, open an issue at https://github.com/aelmanaa/hardhat-kms/issues. |
