neo4j/neo4j · error · UnsupportedOperationException

Not supported in storage channels

Error message

Not supported in storage channels

What it means

StorageChannel implements a positional write API surface (it mirrors Neo4j's ReadableChannel/WritableChannel contracts) but the underlying cloud channel only supports sequential writes — remote storage is typically append/stream oriented and cannot cheaply seek-and-write. writeAll(ByteBuffer, long position) therefore throws UnsupportedOperationException to fail fast on positional semantics.

Source

Thrown at community/cloud/src/main/java/org/neo4j/cloud/storage/StorageChannel.java:77

        return write(srcs, 0, srcs.length);
    }

    @Override
    public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
        Preconditions.checkArgument(
                offset >= 0 && offset < srcs.length, "Offset must be within the range of buffers provided");
        Preconditions.checkArgument(
                offset + length <= srcs.length, "Length must be within the range of buffers provided");
        var written = 0L;
        for (var i = offset; i < offset + length; i++) {
            written += doWrite(srcs[i]);
        }
        return written;
    }

    @Override
    public void writeAll(ByteBuffer src, long position) throws IOException {
        throw new UnsupportedOperationException("Not supported in storage channels");
    }

    @Override
    public void writeAll(ByteBuffer src) throws IOException {
        doWrite(src);
    }

    @Override
    public StorageChannel truncate(long size) throws IOException {
        channel.truncate(size);
        return this;
    }

    @Override
    public int read(ByteBuffer dst, long position) throws IOException {
        //noinspection resource
        return position(position).read(dst);
    }

View on GitHub (pinned to f213380f81)

Solutions

  1. Use the sequential API: position(pos) followed by writeAll(src) (single-argument), which is supported
  2. Rewrite generic copy helpers to check channel type and use sequential writes for StorageChannel
  3. Buffer writes in memory (or a local temp channel) and stream them sequentially to storage

Example fix

// before
channel.writeAll(buffer, 42L); // throws

// after
channel.position(42L);
channel.writeAll(buffer);
Defensive patterns

Strategy: validation

Validate before calling

void writeAllAt(StorageChannel ch, ByteBuffer src, long pos) throws IOException {
    ch.position(pos);          // supported
    ch.writeAll(src);          // sequential overload, supported
}

Type guard

static boolean supportsPositionalWrite(ReadableChannel ch) {
    return !(ch instanceof org.neo4j.cloud.storage.StorageChannel);
}

Try / catch

catch (UnsupportedOperationException e) on writeAll(src, pos): retry once via position(pos)+writeAll(src); rethrow if that also fails.

Prevention

When it happens

Trigger: Calling storageChannel.writeAll(src, position) — the two-argument positional variant — directly, or via framework code that uses positional writes when a channel happens to be a StorageChannel (e.g. generic copy utilities that always call the positional overload).

Common situations: Reusing file-copy or page-flush utilities written against StoreChannel/FileChannel with cloud storage channels; migrating code from LocalFileSystemAbstraction channels to cloud storage; third-party libs that call FileChannel-style positional writes.

Related errors


AI-assisted analysis of neo4j/neo4j@f213380f81 (2026-08-14). Data as JSON: /api/errors/2d30460b428d6c8b. Report an issue: GitHub.