Harel Trabelsi
08/30/2026, 3:12 PM│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py", line 103, in read │
│ for stream_data in self._retriever.read_records( │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py", line 525, in read_records │
│ for stream_data in self._read_pages(record_generator, self.state, _slice): │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py", line 396, in _read_pages │
│ for current_record in records_generator_fn(response): │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py", line 595, in _parse_records │
│ yield from self._parse_response( │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py", line 281, in _parse_response │
│ yield from self.record_selector.select_records( │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/extractors/record_selector.py", line 90, in select_records │
│ yield from self.filter_and_transform( │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/extractors/record_selector.py", line 121, in filter_and_transform │
│ for data in normalized_data: │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/extractors/record_selector.py", line 137, in _normalize_by_schema │
│ yield from records │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/extractors/record_selector.py", line 162, in _transform │
│ for record in records: │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/extractors/record_selector.py", line 154, in _filter │
│ yield from records │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/extractors/dpath_extractor.py", line 72, in extract_records │
│ for body in self.decoder.decode(response): │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py", line 199, in decode │
│ yield from parser.parse(data=io.BytesIO(response.content)) │
│ File "/home/airbyte/.pyenv/versions/3.10.18/lib/python3.10/site-packages/airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py", line 96, in parse │
│ yield json.loads(line.decode(encoding=self.encoding or "utf-8")) │
│ UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte │
How can I fix this?kapa.ai
08/30/2026, 3:12 PM0x8b byte is the second byte of the gzip magic number (0x1f 0x8b), confirming the response has not been decompressed before JSONL parsing.
Solution You need to nest a JsonlDecoder inside a GzipDecoder in your stream's YAML configuration. The GzipDecoder will decompress the response first, then pass the result to the inner decoder. [ZIP and gzip]
retriever:
type: SimpleRetriever
record_selector:
type: RecordSelector
extractor:
type: DpathExtractor
field_path: []
decoder:
type: GzipDecoder
decoder:
type: JsonlDecoder
requester:
...
The GzipDecoder supports nesting the following inner decoders: CsvDecoder, GzipDecoder, JsonDecoder, JsonItemsDecoder, and JsonlDecoder. [GzipDecoder reference]
This pattern is also used in the Amplitude connector, which handles ZIP → GZip → JSONL nesting:
decoder:
type: ZipfileDecoder
decoder:
type: GzipDecoder
decoder:
type: JsonlDecoder
For your case (single gzip layer containing JSONL), only the GzipDecoder wrapping JsonlDecoder is needed. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsHarel Trabelsi
08/30/2026, 3:16 PM- type: DeclarativeStream
retriever:
type: SimpleRetriever
record_selector:
type: RecordSelector
extractor:
type: DpathExtractor
field_path: []
requester:
type: HttpRequester
http_method: GET
url: >-
https://<url>
request_headers: {}
decoder:
type: GzipDecoder
decoder:
type: JsonlDecoder
name: testkapa.ai
08/30/2026, 3:16 PMGzipDecoder wrapping JsonlDecoder) is structurally correct. However, the error trace confirms that the raw gzip bytes (0x8b) are reaching the JsonlDecoder directly, meaning the GzipDecoder decompression step is being skipped.
There are two likely causes:
1. YAML Indentation Issue Your pasted YAML shows retriever: and name: at the same indentation level as type: DeclarativeStream, which would be invalid. Make sure the full stream is properly indented:
streams:
- type: DeclarativeStream
name: test
retriever:
type: SimpleRetriever
record_selector:
type: RecordSelector
extractor:
type: DpathExtractor
field_path: []
requester:
type: HttpRequester
http_method: GET
url_base: "https://<url>"
request_headers: {}
decoder:
type: GzipDecoder
decoder:
type: JsonlDecoder
2. Content-Encoding Header Conflict If the server returns a Content-Encoding: gzip header, the requests library may auto-decompress the body, causing the CDK to mishandle the GzipDecoder pipeline. A known workaround (referenced in a related GitHub issue) is to wrap the decoder in a second GzipDecoder layer:
decoder:
type: GzipDecoder
decoder:
type: GzipDecoder
decoder:
type: JsonlDecoder
[GitHub issue #56988]
I'd recommend verifying your YAML indentation first, as that is the most common cause of decoders not being applied. If the problem persists, try the double GzipDecoder workaround. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsHarel Trabelsi
08/30/2026, 3:19 PM"Content-Type": "application/octet-stream",kapa.ai
08/30/2026, 3:19 PMGzipDecoder only activates when it detects a recognized gzip Content-Type (like application/gzip or application/x-gzip). With application/octet-stream, it skips decompression and passes the raw bytes straight to the inner JsonlDecoder. [GitHub issue #56988] The confirmed workaround is to wrap your decoder in a second GzipDecoder, which causes the CDK to use its default gzip content type and decompress correctly: decoder: type: GzipDecoder decoder: type: GzipDecoder decoder: type: JsonlDecoder This was tested on real data and confirmed working for the same scenario (gzip-compressed response with no Content-Encoding header and a non-standard Content-Type). [GitHub issue #56988] > Note: This is a workaround, not a permanent fix. The proper fix would be on the CDK side to default the content type to gzip for GzipDecoder regardless of the response headers. If this workaround doesn't resolve your issue, it may be worth filing or referencing a CDK bug report. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elements