AttributeError: ‘NumPy NdArray’ Object Has No Attribute ‘Seek’ means a file-like object was expected; pass bytes via io.BytesIO or a real file handle.
The message looks odd at first glance, because a NumPy array is a chunk of memory, not a stream. Functions that read images, audio, models, or CSVs often expect a file path or a file-like stream with methods such as .read(), .seek(), and .tell(). A plain ndarray doesn’t provide those methods, so any library that tries to reposition the stream with seek(0) fails. The fix is simple: give the function what it asked for — a real filename or a file-like buffer — instead of the array object.
What Triggers AttributeError: ‘NumPy NdArray’ Object Has No Attribute ‘Seek’
Quick context: file APIs in Python use seek() to jump around within a stream. When a library like Pillow opens an image from a “file,” it may seek(0) to rewind before decoding. If your code passes an ndarray where a file or buffer was expected, the library calls .seek() on the wrong object and raises this error. Pillow’s docs are clear: if you pass a file object to Image.open, it must implement read, seek, and tell. Python’s own docs explain seek() as the way streams change position. This is why the array fails: it has bytes, but it’s not a stream.
Quick Fixes That Solve It Now
- Wrap bytes in
BytesIO— Convert image or binary data tobytes, then wrap withio.BytesIOand pass that buffer to libraries that expect a file-like object. - Pass a path or open file — Save to a temporary file and pass the path or an opened handle (
rbmode) if the API is path-first and you don’t need in-memory streams. - Use the library’s array path — For OpenCV, decode from bytes with
cv2.imdecode(np.frombuffer(...), ...)or pass a filename tocv2.imreadinstead of the array object. - Feed seekable buffers to loaders — Many loaders (
torch.load, some audio decoders) need a seekable stream; useio.BytesIOor a real file handle. - Check the function signature — Read the docstring: does it want a path, bytes, a buffer, or a NumPy array? Pick the matching input to avoid the
seekcall on arrays.
Fixing ‘Ndarray Has No Seek’ In Pillow, OpenCV, And Torch
Pillow: Image.open With In-Memory Bytes
Use a file-like buffer: if you have raw image bytes (from a request, database, or a previous encode), wrap them in BytesIO so Pillow can seek() safely.
from io import BytesIO
from PIL import Image
# image_bytes = ... # bytes from network/storage
img = Image.open(BytesIO(image_bytes)) # OK: file-like with .seek()
arr = np.asarray(img) # ndarray when you need it
Skip the array as “file”: avoid calling Image.open(ndarray). That’s the pattern that raises the error, since the array lacks stream methods.
OpenCV: Decode From Bytes Or Read From Path
Decode from memory: when you pull an image as bytes, convert to a 1-D array and call cv2.imdecode.
import cv2, numpy as np
# image_bytes = ... # bytes of a JPEG/PNG/etc.
nparr = np.frombuffer(image_bytes, dtype=np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) # BGR image
Use a path for files on disk: for local images, cv2.imread("file.jpg") avoids any need for seek.
PyTorch And Seekable Streams
Make the buffer seekable: loaders that rely on seek() (such as torch.load reading from a stream) need a real file or a BytesIO buffer.
import io, torch
# data_bytes = ... # serialized tensor/model bytes
f = io.BytesIO(data_bytes) # seekable
obj = torch.load(f, map_location="cpu")
Why You See AttributeError: ‘NumPy NdArray’ Object Has No Attribute ‘Seek’
Root cause: the function you call is built to read from a stream. To be stream-friendly, it rewinds with seek(0) or jumps to offsets. A NumPy array is not a stream. Passing the array where a stream or filename is expected makes the next seek() call crash. Pillow, for instance, rewinds file-like inputs on Image.open. Python’s I/O layer defines streams and their methods in io, which is why io.BytesIO is the go-to fix when you have bytes in memory.
Common Patterns That Trigger The Error
- Passing an array to a file API — Code hands
Image.openor an audio reader anndarrayinstead of bytes or a filename; the library calls.seek()and fails. - Skipping the decode step — OpenCV expects encoded bytes fed through
imdecode, not a decoded image passed into a file-based reader. - Using non-seekable buffers — Some custom streams or sockets don’t implement
seek. Loaders that require random access raise the same message. - Mixing PIL and NumPy directions —
Image.openwants a path or file-like;np.asarray(Image.open(...))is the right way to move into array space.
Table: What Each Library Expects And The Safe Input
| Library | What It Expects | Safe Input To Pass |
|---|---|---|
Pillow (Image.open) |
Filename or file-like with read/seek/tell |
path or BytesIO(image_bytes) |
OpenCV (imread/imdecode) |
Path (imread) or encoded bytes (imdecode) |
cv2.imread(path) or cv2.imdecode(np.frombuffer(...)) |
| PyTorch loaders | Seekable file/stream | open(path, "rb") or io.BytesIO(bytes) |
Step-By-Step Debugging Checklist
- Read the function’s docstring — Confirm whether it wants a path, a stream, raw bytes, or an array.
- Print the type you pass — Log
type(x)to verify you’re not handing anndarrayinto a file API by mistake. - Test with a real file — Save to a temp file and call the function. If it works, swap in
BytesIOto keep things in memory. - Wrap bytes when needed — Use
io.BytesIO(blob)to create a seekable buffer for in-memory data. - Switch to the array route — When a library has both file and array paths, pick the array-friendly call (
cv2.imdecode,np.asarray(Image.open(...))). - Guard for
Nonereturns — Some decoders returnNoneon bad input; check and raise a clean error with a one-line hint.
Safe Conversions And Snippets You Can Reuse
Bytes → Pillow Image → NumPy Array
from io import BytesIO
from PIL import Image
import numpy as np
def array_from_image_bytes(image_bytes: bytes) -> np.ndarray:
with BytesIO(image_bytes) as buf:
with Image.open(buf) as im:
return np.asarray(im)
NumPy Array (BGR) → Compressed JPEG Bytes → Back
import cv2, numpy as np
def encode_bgr_to_jpeg_bytes(img_bgr: np.ndarray, quality: int = 90) -> bytes:
ok, enc = cv2.imencode(".jpg", img_bgr, [cv2.IMWRITE_JPEG_QUALITY, quality])
if not ok:
raise ValueError("encode failed")
return enc.tobytes()
def decode_jpeg_bytes_to_bgr(jpeg_bytes: bytes) -> np.ndarray:
nparr = np.frombuffer(jpeg_bytes, dtype=np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
if img is None:
raise ValueError("decode failed")
return img
Seekable Stream For Loaders
import io
def as_seekable(data: bytes) -> io.BytesIO:
buf = io.BytesIO()
buf.write(data)
buf.seek(0)
return buf
Memory And Performance Notes You’ll Care About
Avoid extra copies: when you already have encoded bytes, prefer a decode path that reads from memory (BytesIO or cv2.imdecode). Saving to disk and reopening adds I/O overhead and more copies. When you need an ndarray, let the library do the decode (np.asarray(Image.open(...)) for Pillow or cv2.imdecode for OpenCV). When you need a file-like stream, wrap your bytes and move on.
One More Heading With The Exact Keyword
Final check: if “AttributeError: ‘NumPy NdArray’ Object Has No Attribute ‘Seek’” still appears after these changes, print the parameter types you pass and confirm the callee’s expected input. The message points to the same thing every time: a stream-or-path API received a raw array object.
