OpenFeign/feign · error · DecodeException

${e.getMessage()}

Error message

${e.getMessage()}

What it means

While pulling the next element from the decoded stream, the Jackson parser throws a JacksonException (malformed JSON, unexpected token, IO problem). Jackson3IteratorDecoder converts it into a Feign DecodeException carrying the HTTP status, the message, the request, and the cause. The underlying input stream is closed by the parser at that point, so iteration cannot continue.

Solutions

  1. Catch feign.DecodeException around iteration and inspect getCause() for the Jackson message and location (line/column)
  2. Verify the endpoint actually streams the expected element JSON (test with curl)
  3. Increase/verify proxy and read timeouts so the body is not truncated mid-stream
  4. Confirm Content-Type and charset match what the server sends
  5. Add a Deserializer/mixin if the element shape differs from the DTO

Example fix

// before
Iterator<ItemDto> it = itemsApi.stream();
while (it.hasNext()) { save(it.next()); }
// after
try (Iterator<ItemDto> it = itemsApi.stream()) {
  while (it.hasNext()) {
    try { save(it.next()); }
    catch (DecodeException e) { log.error("stream broke at element", e); break; }
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// cheap pre-flight before iterating
if (response.status() != 200) throw new IllegalStateException("non-200: " + response.status());
String head = peekFirstBytes(response); // must look like '{' or '[' not '<html>'

Try / catch

try (Iterator<ItemDto> it = decoded) {
  while (it.hasNext()) {
    try {
      process(it.next());
    } catch (DecodeException e) {
      log.error("Stream decode failed (status {}): {}", e.status(), e.getCause().getMessage());
      break; // parser closed the stream; iteration cannot continue
    }
  }
}

Prevention

When it happens

Trigger: Iterating the Iterator<T> returned from decode() when the response body contains invalid/truncated JSON, a JSON error payload instead of the expected element shape, or the stream is cut off mid-element (proxy timeout, connection reset).

Common situations: Server returns an HTML/JSON error page with status 200; NDJSON/streaming endpoints that fail midway; charset mismatches producing corrupt bytes; response body empty except whitespace where a value was expected.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/6dae42867f7f2b3f. Report an issue: GitHub.

Appendix: source

Thrown at jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java:170

      try {
        JsonToken jsonToken = parser.nextToken();
        if (jsonToken == null) {
          return null;
        }

        if (jsonToken == JsonToken.START_ARRAY) {
          jsonToken = parser.nextToken();
        }

        if (jsonToken == JsonToken.END_ARRAY) {
          ensureClosed(this);
          return null;
        }

        return objectReader.readValue(parser);
      } catch (JacksonException e) {
        // Input Stream closed automatically by parser
        throw new DecodeException(response.status(), e.getMessage(), response.request(), e);
      }
    }

    @Override
    public T next() {
      if (current != null) {
        T tmp = current;
        current = null;
        return tmp;
      }
      T next = readNext();
      if (next == null) {
        throw new NoSuchElementException();
      }
      return next;
    }

    @Override

View on GitHub (pinned to e2a1e27560)