DELETE from Java SDK throws: The server or request is read-only and cannot accept this write statement

I have a N1QL DELETE statement that works Ok (though slow) when entered directly in the admin console. When I try to run the same N1QL query from Java in my application it throws an error 1000 saying the server or request is read-only… I connect to the server from my code using the same user as in the admin console (the admin user created on setting up the Couchbase server).

Server is: Community Edition 7.1.1 build 3175
Java SDK is: 3.2.0

This is the code I try to run (with the N1QL statement shown in a comment):

	public void removeImportedTrips(String importId) {
		/*
			DELETE
			FROM data
			WHERE type IN ["Catch","FishingTrip","Photo"]
			    AND importid="07-10-2022-36BF513CF8047BE9C12588D40048FC1D"
		 */
		if (StringUtil.isEmpty(importId)) {
			Util.error("Attempt to remove imported data WITHOUT an id!!! Stopping...");
			return;
		}
		StringBuilder sb = new StringBuilder("DELETE FROM " + DataBean.CB_DATA_STORE);
		sb.append(" WHERE " + FN_TYPE + " IN ['" + FORM_NAME + "','" + CatchDAO.DB_TYPE + "','" + PhotoDAO.DB_TYPE + "']");
		sb.append(" AND " + FN_IMPORT_ID + "='" + importId + "'");
		String q = sb.toString();
		Util.debug("Query=" + q);
		QueryResult result = getCluster().query(q, getQueryParams());
		System.out.println("result: " + result);
	}

and I get the cluster in this way:

	private Collection getDefaultCollection(Cluster clust) {
		Collection coll = null;
		if (null != clust) {
			Util.trace("Get handle to Couchbase DB/collection");
			Bucket bucket = clust.bucket(CB_DATA_STORE);
			coll = bucket.defaultCollection();
			Util.trace("Got handle to default collection");
		}
		return coll;
	}

	public Cluster getCluster() {
		if (null == cluster) {
			cluster = Cluster.connect(ConfigurationBean.get().getDatabaseServerNames() + "?" + timeoutOpts, CB_DATA_USER, CB_DATA_PASSWORD);
			Util.info("Got handle to cluster: " + ConfigurationBean.get().getDatabaseServerNames());
			db = getDefaultCollection(cluster);
		}
		return cluster;
	}

This was originally developed using Java SDK 2.x and therefore we have tried to limit the changes when upgrading to 3.x.

I create documents and update documents fine with the similar code. And I remove individual documents as well (using the .remove(docid) method - so I should have sufficient access for the user…

The stack trace I get when running the query from Java is:

Caused by: com.couchbase.client.core.error.CouchbaseException: Unknown query error {"completed":true,"coreId":"0xe0a94f4000000001","errors":[{"code":1000,"message":"The server or request is read-only and cannot accept this write statement."}],"idempotent":true,"lastDispatchedFrom":"192.168.42.226:54722","lastDispatchedTo":"db2.dalsgaard-data.dk:8093","requestId":182838,"requestType":"QueryRequest","retried":0,"service":{"operationId":"ca80fef4-23f2-4787-a54d-3686a6e8dfe0","statement":"DELETE FROM data WHERE type IN ['FishingTrip','Catch','Photo'] AND importid='07-10-2022-0DC52BA78BE3976DC12588D400487096'","type":"query"},"timeoutMs":75000,"timings":{"dispatchMicros":24002,"totalDispatchMicros":24002,"totalMicros":47087}}
	at com.couchbase.client.java.AsyncUtils.block(AsyncUtils.java:51)
	at com.couchbase.client.java.Cluster.query(Cluster.java:393)
	at dk.dtu.aqua.catchlog.dao.CouchbaseFishingTripDAO.removeImportedTrips(CouchbaseFishingTripDAO.java:582)
	at dk.dtu.aqua.catchlog.dao.facade.FishingTripCRUDFacade.removeAllImportedWithId(FishingTripCRUDFacade.java:794)
	at dk.dtu.aqua.catchlog.bean.ImporterBean.removeImport(ImporterBean.java:69)
	at dk.dtu.aqua.catchlog.bean.ImporterBean.deleteImport(ImporterBean.java:44)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:90)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
	at java.lang.reflect.Method.invoke(Method.java:508)
	at com.ibm.jscript.types.JavaAccessObject.call(JavaAccessObject.java:322)
	... 45 more
	Suppressed: java.lang.Exception: The above exception was originally thrown by another thread at the following location.
		at com.couchbase.client.core.io.netty.query.QueryChunkResponseParser.errorsToThrowable(QueryChunkResponseParser.java:158)
		at com.couchbase.client.core.io.netty.query.QueryChunkResponseParser$$Lambda$366.00000000C0F96590.apply(Unknown Source)
		at java.util.Optional.map(Optional.java:226)
		at com.couchbase.client.core.io.netty.query.QueryChunkResponseParser.error(QueryChunkResponseParser.java:120)
		at com.couchbase.client.core.io.netty.chunk.ChunkedMessageHandler.lambda$maybeCompleteResponseWithFailure$1(ChunkedMessageHandler.java:283)
		at com.couchbase.client.core.io.netty.chunk.ChunkedMessageHandler$$Lambda$365.00000000C0F9A600.get(Unknown Source)
		at java.util.Optional.orElseGet(Optional.java:278)
		at com.couchbase.client.core.io.netty.chunk.ChunkedMessageHandler.maybeCompleteResponseWithFailure(ChunkedMessageHandler.java:282)
		at com.couchbase.client.core.io.netty.chunk.ChunkedMessageHandler.channelRead(ChunkedMessageHandler.java:214)
		at com.couchbase.client.core.deps.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
		at com.couchbase.client.core.deps.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
		at com.couchbase.client.core.deps.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
		at com.couchbase.client.core.deps.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
		at com.couchbase.client.core.deps.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
		at com.couchbase.client.core.deps.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
		at com.couchbase.client.core.deps.io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
		at com.couchbase.client.core.deps.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
		at com.couchbase.client.core.deps.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
		at com.couchbase.client.core.deps.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
		at com.couchbase.client.core.deps.io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
		at com.couchbase.client.core.deps.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
		at com.couchbase.client.core.deps.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
		at com.couchbase.client.core.deps.io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
		at com.couchbase.client.core.deps.io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:795)
		at com.couchbase.client.core.deps.io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480)
		at com.couchbase.client.core.deps.io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378)
		at com.couchbase.client.core.deps.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
		at com.couchbase.client.core.deps.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
		at com.couchbase.client.core.deps.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
		at java.lang.Thread.run(Thread.java:811)

What could I be doing wrong here??

If I rewrite the code to select all meta ids of the same documents and call

getDb().remove(id)

for each document then they are all removed correctly…

The getDb() method just returns the collection cached in the getCluster() method (above).

For other’s reference this was posted on Discord too, and it turns out the QueryOptions.readonly() flag is applied.

2 Likes

Ouch… just found that I set the query params to readonly(true) - probably back when I looked at forcing a re-read of index and still trying to keep performance high.

That is obviously why using the methods directly on the collection work. :blush:

1 Like