---
title: "Cenários de erro 400 (BadRequest) na emissão de NFS-e"
description: "Catálogo dos cenários em que a API de NFS-e retorna HTTP 400 (BadRequest) na emissão e nas operações da nota, com a regra violada e como corrigir."
source_url: https://nfe.io/docs/documentacao/nota-fiscal-servico-eletronica/duvidas/erros-e-status/cenarios-de-badrequest-na-emissao
last_updated: 2026-07-03
---

# Cenários de erro 400 (BadRequest) na emissão de NFS-e

Esta página lista os cenários em que a API de NFS-e responde **HTTP 400 (BadRequest)** ao emitir uma nota ou ao cancelá-la. Um 400 significa que a requisição foi rejeitada por **validação de payload** ou por **regra de negócio** — antes de a nota ser enviada à prefeitura.

Para a visão geral de todos os status HTTP (401, 408, 500, 503, 504), consulte [Tipos de retorno de status das requisições HTTPS](./tipos-de-retorno-de-status-das-requisicoes-https.md). Para diagnóstico passo a passo por sintoma, consulte [Solução de erros 400 na emissão de NFS-e](./solucao-de-erros-400-na-emissao.md).

## Como interpretar o corpo do erro 400

Existem **dois tipos** de erro 400, com corpos diferentes:

### Validação de formato (desserialização do JSON)

Quando o corpo enviado não pode ser interpretado — JSON malformado ou tipo incompatível (por exemplo, enviar `federalTaxNumber` ou `servicesAmount` como texto não numérico) — a API responde 400 com um corpo **ProblemDetails** (JSON estruturado), antes de qualquer regra de negócio. As chaves de `errors` são o caminho do campo no JSON (`$.campo`):

```json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "$.borrower.federalTaxNumber": [
      "The JSON value could not be converted to System.Int64. Path: $.borrower.federalTaxNumber | LineNumber: 0 | BytePositionInLine: 736."
    ]
  },
  "traceId": "00-<trace-id>-<span-id>-00"
}
```

### Regras de negócio (validação e estado)

Os cenários das tabelas abaixo retornam um corpo de **texto simples**, em uma destas formas:

- **Mensagem única** — uma frase descrevendo a regra violada. Exemplo: `Municipal tax is not allowed to issue invoice`.
- **Lista de mensagens** — quando vários campos falham na mesma requisição, as mensagens vêm concatenadas (uma por regra violada).
- **Sem corpo** — alguns cenários retornam 400 com corpo vazio. Nesses casos, identifique a causa pela operação e pelo contexto da requisição (ver coluna "Mensagem retornada" marcada como _sem corpo_).

:::note
As mensagens de negócio são retornadas em inglês, exatamente como nas tabelas abaixo. Trate-as como literais ao exibir para o usuário final ou ao casar por texto em automações.
:::

## Validação do payload de emissão

Disparados ao validar o corpo do `POST /v1/companies/{companyId}/serviceinvoices`. Quando mais de uma regra falha, as mensagens são agregadas em uma única resposta.

| Campo / regra | Condição que dispara o 400 | Mensagem retornada | Como evitar |
|---|---|---|---|
| `Body` | corpo da requisição nulo | `Body can not be null` | Envie um corpo JSON válido |
| `cityServiceCode` | nulo ou vazio | `cityServiceCode can not be null or empty` | Informe o código de serviço municipal |
| `description` | nula ou vazia | `description can not be null or empty` | Informe a descrição do serviço |
| `servicesAmount` | `< 0` | `servicesAmount can not be less than 0.00` | Use valor de serviço `>= 0` |
| `rpsSerialNumber` | informado com comprimento 0 | `rpsSerialNumber can not be less than zero` | Omita o campo ou informe uma série não vazia |
| `rpsNumber` | informado `<= 0` | `rpsNumber can not be less than or equal zero` | Use número de RPS `> 0` |
| `issRate` | `< 0` | `issRate can not be less than 0.00 (0%)` | Use alíquota entre 0% e 5% |
| `issRate` | `> 0,05` | `issRate can not be more than 0.05 (5%)` | Use alíquota `<= 0.05` (5%) |
| `deductionsAmount` | `< 0` | `deductionsAmount can not be less than zero` | Use valor `>= 0` |
| `discountConditionedAmount` | `< 0` | `discountConditionedAmount can not be less than zero` | Use valor `>= 0` |
| `discountUnconditionedAmount` | `< 0` | `discountUnconditionedAmount can not be less than zero` | Use valor `>= 0` |
| `irAmountWithheld` | `< 0` | `irAmountWithheld can not be less than zero` | Use valor `>= 0` |
| `pisAmountWithheld` | `< 0` | `pisAmountWithheld can not be less than zero` | Use valor `>= 0` |
| `cofinsAmountWithheld` | `< 0` | `cofinsAmountWithheld can not be less than zero` | Use valor `>= 0` |
| `csllAmountWithheld` | `< 0` | `csllAmountWithheld can not be less than zero` | Use valor `>= 0` |
| `inssAmountWithheld` | `< 0` | `inssAmountWithheld can not be less than zero` | Use valor `>= 0` |
| `issAmountWithheld` | `< 0` | `issAmountWithheld can not be less than zero` | Use valor `>= 0` |
| `othersAmountWithheld` | `< 0` | `othersAmountWithheld can not be less than zero` | Use valor `>= 0` |
| `approximateTax.totalRate` | `< 0` | `approximateTax.TotalRate can not be less than 0.00 (0%)` | Use percentual `>= 0` |
| `approximateTax.totalRate` | `> 99,99` | `approximateTax.TotalRate can not be more than 99.99 (99.99%)` | Use percentual `<= 99.99` |
| `ibsCbs.classCode` | informado e diferente de 6 dígitos | `ibsCbs.classCode must be exactly 6 digits` | Informe exatamente 6 dígitos |
| `ibsCbs.operationIndicator` | informado e diferente de 6 dígitos | `ibsCbs.operationIndicator must be exactly 6 digits` | Informe exatamente 6 dígitos |
| `construction.encapsulationNumber` | informado fora de 1 a 12 dígitos | `construction.encapsulationNumber must contain from 1 to 12 digits` | Informe de 1 a 12 dígitos |
| `additionalInformation` | comprimento `> 500` | `additionalInformation length must be less than 500 characters` | Limite o texto a 500 caracteres |
| `location.city` | `location` presente com `city` nulo | `location.city can not be null` | Informe a cidade do local da prestação |
| `location.city.code` | nulo ou vazio | `location.city.code can not be null or empty` | Informe o código IBGE da cidade |
| `location.city.code` | diferente de 7 dígitos | `location.city.code must be a valid IBGE city code` | Use o código IBGE de 7 dígitos |
| `location.city.name` | nula ou vazia | `location.city.name can not be null or empty` | Informe o nome da cidade |
| `location.state` | nula ou vazia | `location.state can not be null or empty` | Informe a UF |
| `location.state` | diferente de 2 caracteres | `location.state must be a valid ISO 3166-2 code, samples (SP, RJ, AC)` | Use a sigla da UF com 2 letras |
| `borrower.name` | comprimento `> 115` | `borrower.name length must be less than 115 characters` | Limite o nome a 115 caracteres |
| `borrower.federalTaxNumber` | tomador no Brasil sem CPF nem CNPJ válido | `borrower.federalTaxNumber borrower federal tax number is not valid` | Informe CPF ou CNPJ válido |
| `borrower.federalTaxNumber` | tipo `NaturalPerson` com CPF inválido | `borrower.federalTaxNumber is not valid for natural person` | Use CPF válido para pessoa física |
| `borrower.federalTaxNumber` | tipo `LegalEntity` com CNPJ inválido | `borrower.federalTaxNumber is not valid for legal person` | Use CNPJ válido para pessoa jurídica |
| `borrower.phoneNumber` | informado com menos de 7 dígitos | `borrower.phoneNumber can not be less than 7 digits` | Use telefone com 7 a 19 dígitos |
| `borrower.phoneNumber` | informado com 20 dígitos ou mais | `borrower.phoneNumber can not be longer than 20 digits` | Use telefone com no máximo 19 dígitos |

:::tip
Tomador estrangeiro (`borrower.address.country` diferente de `BRA`) pula a validação de CPF/CNPJ. Use o `country` correto para evitar rejeição indevida do documento fiscal.
:::

:::note
A ausência do bloco `borrower` **não** retorna 400 na emissão. Ainda assim, informe o tomador: ele é necessário para a nota ser concluída — sem ele, a validação ocorre apenas adiante (consulta da nota/prefeitura).
:::

### Endereço do tomador (quando `country` = `BRA`)

Disparados por `ValidateAddress`. Um endereço totalmente vazio é aceito; ao informar qualquer campo, os demais passam a ser exigidos.

| Campo / regra | Condição que dispara o 400 | Mensagem retornada | Como evitar |
|---|---|---|---|
| `borrower.address.country` | código fora da tabela ISO 3166-1 | `borrower.address.country must be a valid ISO 3166-1 code, samples (BRA, ARG, COL)` | Use o código de país de 3 letras |
| `borrower.address.postalCode` | nulo ou vazio | `borrower.address.postalCode can not be null or empty` | Informe o CEP |
| `borrower.address.street` | nulo ou vazio | `borrower.address.street can not be null or empty` | Informe o logradouro |
| `borrower.address.city` | nula | `borrower.address.city can not be null` | Informe a cidade |
| `borrower.address.state` | nula ou vazia | `borrower.address.state can not be null or empty` | Informe a UF |
| `borrower.address.state` | diferente de 2 caracteres ou com espaço | `borrower.address.state must be a valid ISO 3166-2 code, samples (SP, RJ, AC)` | Use a sigla da UF com 2 letras |
| `borrower.address.city.code/name` | código **ou** nome da cidade vazio | `borrower.address.city.code or borrower.address.city.name can not be null or empty` | Informe código IBGE e nome |
| `borrower.address.city.code` | diferente de 7 dígitos | `borrower.address.city.code must be a valid IBGE city code` | Use o código IBGE de 7 dígitos |
| `borrower.address.state` | UF inexistente na base | `borrower.address.state is not a valid state code` | Use uma UF válida |
| `borrower.address.city.code` | cidade inexistente na base | `borrower.address.city.code is not a valid city code or city` | Use um código IBGE existente |
| `borrower.address.city.code` + `state` | UF não corresponde ao prefixo do código IBGE | `borrower.address.city.code and borrower.address.state aren't related. inform the correct state associated with correct city code` | Garanta que cidade e UF sejam coerentes |
| `borrower.address.state` | UF da base difere da informada | `borrower.address.state from DB differs of city state informed` | Garanta que cidade e UF sejam coerentes |

### Comércio exterior (`foreignTrade`)

Validados apenas quando o bloco `foreignTrade` é informado.

| Campo / regra | Condição que dispara o 400 | Mensagem retornada | Como evitar |
|---|---|---|---|
| `foreignTrade.serviceMode` | valor fora do enum | `foreignTrade.serviceMode is invalid` | Use um valor de enum válido |
| `foreignTrade.relationShip` | valor fora do enum | `foreignTrade.relationShip is invalid` | Use um valor de enum válido |
| `foreignTrade.currency` | nula ou vazia | `foreignTrade.currency can not be null or empty` | Informe a moeda |
| `foreignTrade.serviceAmountInCurrency` | nulo | `foreignTrade.serviceAmountInCurrency can not be null` | Informe o valor em moeda estrangeira |
| `foreignTrade.serviceAmountInCurrency` | `< 0` | `foreignTrade.serviceAmountInCurrency can not be less than zero` | Use valor `>= 0` |
| `foreignTrade.supportMechanismProvider` | valor fora do enum | `foreignTrade.supportMechanismProvider is invalid` | Use um valor de enum válido |
| `foreignTrade.supportMechanismReceiver` | valor fora do enum | `foreignTrade.supportMechanismReceiver is invalid` | Use um valor de enum válido |
| `foreignTrade.temporaryGoods` | valor fora do enum | `foreignTrade.temporaryGoods is invalid` | Use um valor de enum válido |
| `foreignTrade.mdicDelivery` | nulo | `foreignTrade.mdicDelivery can not be null` | Informe o indicador de entrega ao MDIC |

## Regras de emissão

Disparados de forma **síncrona** depois da validação do payload, no `POST /v1/companies/{companyId}/serviceinvoices`. Quando a mensagem é _sem corpo_, identifique a causa pelo contexto da empresa.

| Cenário | Condição que dispara o 400 | Mensagem retornada |
|---|---|---|
| Imposto municipal inativo | habilitação fiscal da empresa diferente de "ativa" (em produção) | `Municipal tax is not allowed to issue invoice` |
| Empresa inativa | empresa com status diferente de "ativa" | `company is not active` |
| RPS duplicado | já existe nota com o mesmo número de RPS | `service invoice with rps number ({rpsNumber}) already exists` |
| `externalId` duplicado | já existe nota com o mesmo `externalId` | `service invoice with external id ({externalId}) already exists` |
| Corpo da nota nulo | requisição sem dados da nota | _sem corpo_ |

:::warning
RPS ou `externalId` duplicado pode retornar **400** (e não 409). Não trate duplicidade assumindo um código de status fixo; verifique a mensagem retornada.
:::

:::note
Outras validações (certificado digital, habilitação por código de serviço, regravação) ocorrem **após o enfileiramento**, no processamento assíncrono da nota. Elas **não** retornam 400 na chamada de emissão — o resultado é entregue na consulta da nota, no `status` e na mensagem de fluxo.
:::

## Cancelamento da nota

| Operação | Condição que dispara o 400 | Mensagem retornada |
|---|---|---|
| Cancelamento (`DELETE /{id}`) | imposto municipal inativo (em produção) | `Municipal tax is not allowed to issue invoice` |

## Veja também

- [Tipos de retorno de status das requisições HTTPS](./tipos-de-retorno-de-status-das-requisicoes-https.md)
- [Solução de erros 400 na emissão de NFS-e](./solucao-de-erros-400-na-emissao.md)
- [Campos de autorização NFSe](../campos-de-autorizacao-nfse.md)

## Para IA / LLMs

- **Cobertura:** cenários que fazem a API de NFS-e responder HTTP 400 (BadRequest) na emissão e no cancelamento da nota.
- **Versão aplicável:** API de NFS-e v1. Regras de validação são da plataforma NFE.io; a rejeição da prefeitura é posterior e não gera 400.
- **Não parafrasear:** a coluna "Mensagem retornada" é **literal** (retornada em inglês pela API). Reproduza a mensagem original ao responder; a coluna "Como evitar" pode ser interpretada.
- **Corpo do erro:** dois tipos. Validação de formato/desserialização → ProblemDetails JSON (`{ "errors": {...}, "status": 400 }`). Regras de negócio → texto simples (mensagem única ou lista concatenada) ou **vazio**.
- **Síncrono vs assíncrono:** só os cenários listados retornam 400 na chamada. Certificado, código de serviço e regravação ocorrem no processamento assíncrono e não viram 400 — chegam na consulta da nota.
- **Pré-requisitos:** [Tipos de retorno de status das requisições HTTPS](./tipos-de-retorno-de-status-das-requisicoes-https.md).
- **Atualizado:** 2026-06-27 por revisão humana.
