Trouble saving attachment via CBL Listener (REST API)


I am trying to save an attachment through the CBL REST API, but get an “Invalid attachment” response with a 400 http status. Saving/Updating/Querying/Deleting documents work fine.

Here is the output when I enable logging with the CBLListenerVerbose tag:

Here is my code in javascript (it is a ReactNative app):

fetch(couchbaseURL + documentID + "?rev=" + documentRevision, {
    method: "PUT",
    body: "This is my text",
    headers: { "Content-Type": "text/plain" }
}).then(function(response){ ... });

Do I do something wrong ? How can I get more information about why the attachment is invalid ?

Many thanks for your help,


It looks like you’re saving a document, not an attachment, except you’re sending the body as plain text instead of JSON. If you want to create an attachment through a REST call, the easiest way is to do a PUT to the URL of the attachment. That means you need to add the attachment name as a component of the URL. In your example, change the first line to

fetch(couchbaseURL + documentID + "/" + attachmentName + "?rev=" + documentRevision, {

Many thanks for the quick reply. This is a typo on my part : the actual URL i use includes the attachment name as you wrote it:

fetch(couchbaseURL + documentID + "/note.txt" + "?rev=" + documentRevision, {

It looks correct as far as I can tell, but I don’t know the JavaScript API. Is there a way you can find out exactly what headers and body are being sent? (Whatever you did to turn on CBLListenerVerbose logging didn’t work, or it would have logged that.)

Also: Are you certain the document already exists? (If it doesn’t exist, you have to leave off the ?rev= query.)

OK, I’ll try to figure out what headers and body are being sent, thanks.

I enabled logging with

[CBLManager enableLogging: @"CBLListenerVerbose"];

in application didFinishLaunchingWithOptions in the AppDelegate file.

I think the document exists, as wrapping the above code in a GET call to retrieve the document with the given id and revision returns the document and yields the same result.

Ah, there’s an annoying bug that prevents listener logging options from being set by CBLManager. If you have access to the command-line flags (i.e. if you’re running the app from an Xcode project) you can add -Log YES -Log CBLListenerVerbose as flags.

Sorry to ask you this - but the output of logging is to be found in the Xcode console right ?

I added the two flags and the only new output I can find is

Logging CBLListener, CBLListenerVerbose to TTY

thanks again for your help

In case it can help, here is the logs output after enabling CBL_Router

10:31:30.414‖ CBL_Router: PUT http://lite.couchbase./planity/416410a3-8cd7-4e78-9684-e86346f49a74/attachment.txt?rev=1-191cf9b2c01471114a2bbef24f77aab8 + body stream
Content-Type: text/plain
Content-Length: 15

10:31:30.415‖ CBL_BlobStore /Users/paul/Library/Developer/CoreSimulator/Devices/20578BD8-AE31-44B4-BB28-1593199B61C0/data/Containers/Data/Application/86111FD6-DE95-4AE4-B469-6DAAA9D28336/Library/Application Support/CouchbaseLite/planity attachments created tempDir /Users/paul/Library/Developer/CoreSimulator/Devices/20578BD8-AE31-44B4-BB28-1593199B61C0/data/Containers/Data/Application/86111FD6-DE95-4AE4-B469-6DAAA9D28336/Library/Application Support/CouchbaseLite/(A Document Being Saved By PlanityIOSApp 24)

10:31:30.416‖ CBL_Router: Response – status=400, body=43 bytes
Server: CouchbaseLite 1.0 (unofficial)
Content-Type: application/json


I tried this from the Chrome console and the attachment is saved correctly in CBLite (v1.0.4).
Is the request working in the Chrome console for you?

var url = 'http://localhost:64943/db';
// add attachment to existing doc
fetch(url + '/doc-1234/notes.txt?rev=2-99de4882df335ecae91a75a9b2bb930c',
 {method: 'PUT', body: 'some text', headers: { 'Content-Type': 'text/plain' }})
.then(function(res) {
  return res.json();
.then(function(jsonRes) {

// console.log output
Object {id: "doc-1234", rev: "3-76d42a0a45568bdbad4fc698fa04b1bb", ok: true}

Hi, same result for me from the Chrome console:

fetch('http://lite.couchbase./planity/416410a3-8cd7-4e78-9684-e86346f49a74/attachment.txt?rev=1-191cf9b2c01471114a2bbef24f77aab8',{method: 'PUT', body: 'some text', headers: { 'Content-Type': 'text/plain' }})
.then(function(res) {
  return res.json();
.then(function(jsonRes) {

// console.log output
Object {status: 400, error: "Invalid attachment"}

I am also using CBLite 1.4.0

We didn’t have a unit test covering this exact situation (PUT to an attachment URL for a doc that already exists), but I just wrote one and it runs successfully.

Hi, same result for me from the Chrome console:

I don’t see how the code you show can work in the Chrome console, because “lite.couchbase.” isn’t a valid hostname except inside an app using Couchbase Lite. Please show the exact text you ran in Chrome.

This is the exact code. The Chrome console thing is a feature of ReactNative : it lets you execute some js in the context of the app.

I tried a PUT request to an attachment URL for a doc not yet existing - with the same result.

Ah, got it. Sorry for misunderstanding.

I don’t know why it’s not working for you. But in any case, this is not the best way to create an attachment, it’s just a convenience. The best way is to PUT the document with an _attachment property containing the metadata and data of the attachment(s). I don’t know if our own REST docs cover this in enough detail, but it’s identical to CouchDB and there’s plenty of documentation of that.

@jamiltz I would be curious to know your setup : what version of RN are you using ? Is it an app created with the react-native init command or did you add it to an existing app ? What edition of CB lite are you using? Thanks a lot.

@jens ok, thanks for the info.

Putting with the _attachments property seems to work ok, but when I update the document without including again the attachments, they seem to be deleted : is this the intended behavior ?

Also, can I use this documentation of CouchDB in general for CBL Listener ? Thanks.

Sorry I tried the fetch api available in the latest version of Chrome. I will try in a React Native app and let you know the result.


The _attachments property is part of the document. Any time you save a new revision of the document, it has to include all the properties you want to be in the document; it’s not incremental. In other words, you have to preserve the _attachments property (unless you want to remove some or all of the attachments, of course.)

In general, you update documents incrementally by first doing a GET, modifying the properties you want to change, then PUTting those.

@jens OK, very clear. Thanks a lot for all your help.

@jamiltz that would be very kind of you. I’m still intrigued why the first method didn’t work for me. Many thanks.

Does any one know how to PUT an image attachment via the REST API? How should the body be encoded?