# 415 error when uploading ndjson to kibana

**URL:** <https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455>\
**Category:** Kibana\
**Created:** [March 24, 2023, 11:51am UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455 "2023-03-24T11:51:21Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![amesl](https://avatars.discourse-cdn.com/v4/letter/a/e0b2c6/32.png) [@amesl](https://discuss.elastic.co/u/amesl)\
**Post date:** [March 24, 2023, 11:51am UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/1 "2023-03-24T11:51:21Z")

</div>

I need to upload an ndjson dashboard file to the kibana endpoint in Java. The below command is successful with the ndjson files:

curl -X POST api/saved\_objects/\_import?overwrite=true -H "kbn-xsrf: true" --form file=@file.ndjson

When calling the curl command from Java with the ndjson files it runs successfully, however we would prefer to use Java connections. When attempting to do the same thing with an HttpsURLConnection we receive the 415 error (Unsupported media type) with the same files.

Any ideas why this continues to return 415 error? We are using kibana 8.4.2

```auto
							    URL url = new URL("https://" + host + "/api/saved_objects/_import?overwrite=true");
							    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
							    conn.setDoOutput(true);
							    conn.setDoInput(true);
							    conn.setUseCaches(false);
	
							    conn.setRequestMethod("POST");
							    conn.setRequestProperty("kbn-xsrf", "true");
							    conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, "application/x-ndjson; charset=utf-8");
							    conn.setRequestProperty(HttpHeaders.ACCEPT, "*/*");
							   
                                // Reads in ndjson file 
							    String json = Files.readString(file.toPath());
							    try (OutputStream os = conn.getOutputStream())
							    {
							    	byte[] input = json.getBytes("utf-8");
							    	os.write(input);
							    	os.flush();
								    os.close();
							    }
							    							    						    							    
							    int responseCode = conn.getResponseCode();
							    String response = conn.getResponseMessage();

```

---

<div class="post-metadata">

**Author:** ![gsoldevila](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/gsoldevila/32/107150_2.png) [@gsoldevila](https://discuss.elastic.co/u/gsoldevila)\
**Post date:** [March 27, 2023, 12:45pm UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/2 "2023-03-27T12:45:45Z")

</div>

Hello, and welcome to the community!

I believe the problem is that the [/api/saved\_objects/\_import](https://github.com/elastic/kibana/blob/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/import.ts#L42) endpoint expects the request to be of type `multipart/form-data`.

Please note that this affects the way your NDJSON is appended to the request. The Java API provides the necessary tools for that approach, and there are [some examples](https://blog.cpming.top/p/httpurlconnection-multipart-form-data) of usage on the internet. Please let us know if you have any trouble attaching your NDJSON that way.

Kind regards

---

<div class="post-metadata">

**Author:** ![amesl](https://avatars.discourse-cdn.com/v4/letter/a/e0b2c6/32.png) [@amesl](https://discuss.elastic.co/u/amesl)\
**Post date:** [March 27, 2023, 2:32pm UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/3 "2023-03-27T14:32:31Z")

</div>

Thanks, and I appreciate your response.

I modified the code to handle the ndjson files as multipart files (using the HttpPostMultipart class) but the connection is returning 400 errors. The error is being returned from the line:

```auto
throw new IOException("Server returned non-OK status: " + status);

```

I added some logging to the HttpPostMultipart class and found that the Content-Type is set to null:

```auto
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(fileName)).append(LINE);

```

The URLConnection.guessContentTypeFromName returns null for the \*.ndjson file names.

Since the URLConnection.guessContentTypeFromName returns null should it be hardcoded? The files are ndjson format.

---

<div class="post-metadata">

**Author:** ![gsoldevila](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/gsoldevila/32/107150_2.png) [@gsoldevila](https://discuss.elastic.co/u/gsoldevila)\
**Post date:** [March 29, 2023, 8:13am UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/4 "2023-03-29T08:13:36Z")

</div>

Hello!

I am not familiar with the `HttpPostMultipart` class, is it part of the standard Java API?

When using multipart POST, the _Content-Type_ header should have the `multipart/form-data` value.  
If the library you are using is not setting it for you, then you might have to hardcode it.

Kind regards

---

<div class="post-metadata">

**Author:** ![amesl](https://avatars.discourse-cdn.com/v4/letter/a/e0b2c6/32.png) [@amesl](https://discuss.elastic.co/u/amesl)\
**Post date:** [March 29, 2023, 10:21am UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/5 "2023-03-29T10:21:35Z")

</div>

I truly appreciate your responses! Any response is better than none 🙂

The HttpPostMultipart class is the code from the example you [linked](https://blog.cpming.top/p/httpurlconnection-multipart-form-data) to. The first part shows how to write the HttpPostMultipart class.

In the HttpPostMultipart class example the Content-Type header is hardcoded to multipart/form-data, this is the header on the multipart/form-data message:

```auto
httpConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

```

However, in the addFilePart method that attaches the file the Content-Type is pulled from the file type.

```auto
writer.append("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + fileName + "\"").append(LINE);
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(fileName)).append(LINE);
writer.append("Content-Transfer-Encoding: binary").append(LINE);

```

I changed this to the following because the URLConnection.guessContentTypeFromName(fileName) returned null:

```auto
writer.append("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + fileName + "\"").append(LINE);
writer.append("Content-Type: application/x-ndjson").append(LINE);
writer.append("Content-Transfer-Encoding: binary").append(LINE);

```

So the headers on the POST would look like:

```auto
Content-Type: multipart/form-data; boundary=XXXX
...

Content-Disposition: form-data; name=updateFile; filename=dashboard1.ndjson
Content-Type: application/x-ndjson
Content-Transfer-Encoding: binary
...

```

Each form or message in the multipart message should have a header indicating the contents. The kibana endpoint is returning 400 for messages at this point.

---

<div class="post-metadata">

**Author:** ![gsoldevila](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/gsoldevila/32/107150_2.png) [@gsoldevila](https://discuss.elastic.co/u/gsoldevila)\
**Post date:** [March 29, 2023, 10:47am UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/6 "2023-03-29T10:47:00Z")

</div>

Sorry I just posted the link as an illustrative example, did not pay too much attention to the class names.

Comparing your requests against the ones performed by Kibana UI when using the _Import_ feature, there's a couple differences:

- The name of the form field is simply `"file"` instead of the `"updateFile"` you are currently using. I believe that should make a difference (considering [this validation](https://github.com/elastic/kibana/blob/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/import.ts#L60)).
- The _Content-Transfer-Encoding_ header is not sent by the UI, so we can get rid of it probably.

Kind regards

---

<div class="post-metadata">

**Author:** ![amesl](https://avatars.discourse-cdn.com/v4/letter/a/e0b2c6/32.png) [@amesl](https://discuss.elastic.co/u/amesl)\
**Post date:** [March 29, 2023, 11:13am UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/7 "2023-03-29T11:13:29Z")

</div>

Thank you - I'll certainly try this out.

---

<div class="post-metadata">

**Author:** ![amesl](https://avatars.discourse-cdn.com/v4/letter/a/e0b2c6/32.png) [@amesl](https://discuss.elastic.co/u/amesl)\
**Post date:** [March 29, 2023, 1:33pm UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/8 "2023-03-29T13:33:25Z")

</div>

@gsoldevila THANK YOU! That was the secret sauce to getting this working. Changing the form field to "file" and getting rid of the Content-Transfer-Encoding header were the missing pieces.

---

<div class="post-metadata">

**Author:** ![amesl](https://avatars.discourse-cdn.com/v4/letter/a/e0b2c6/32.png) [@amesl](https://discuss.elastic.co/u/amesl)\
**Post date:** [March 29, 2023, 2:27pm UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/9 "2023-03-29T14:27:16Z")

</div>

Just to document what worked in Java to upload the ndjson files to Kibana. Our server is https and we used a username and password for authentication.

Use the link referenced in first response then made the following changes

Implementing the HttpPostMultipart in the application:

```auto
URL url = new URL("https://" + host + "/api/saved_objects/_import?overwrite=true");

Map<String, String> headers = new HashMap<>();
headers.put(HttpHeaders.AUTHORIZATION, getBasicAuthenticationHeader(user, password));
headers.put("kbn-xsrf", "true");
						    		
HttpPostMultipart multipart = new HttpPostMultipart(url.toString(), "utf-8", headers);
// has to be named file to work with Kibana - the file value is a File object
multipart.addFilePart("file", file);
							    
String response = multipart.finish();

```

Modified the addFilePart method in the HttpPostMultipart class to work for Kibana POST.

- Set the Content-Type to application/x-ndjson
- removed the Content-Transfer-Encoding

```auto
public void addFilePart(String fieldName, File uploadFile) throws IOException 
{
    String fileName = uploadFile.getName();
    writer.append("--" + boundary).append(LINE);
    writer.append("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + fileName + "\"").append(LINE);
    writer.append("Content-Type: application/x-ndjson").append(LINE);
    writer.append(LINE);
    writer.flush();

```

These configurations worked for me.

---

<div class="post-metadata">

**Author:** ![gsoldevila](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/gsoldevila/32/107150_2.png) [@gsoldevila](https://discuss.elastic.co/u/gsoldevila)\
**Post date:** [March 29, 2023, 2:59pm UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/10 "2023-03-29T14:59:26Z")

</div>

Thanks for sharing your working configuration! I'm sure it'll be very useful for future reference.

Cheers

---

<div class="post-metadata">

**Author:** ![amesl](https://avatars.discourse-cdn.com/v4/letter/a/e0b2c6/32.png) [@amesl](https://discuss.elastic.co/u/amesl)\
**Post date:** [March 29, 2023, 3:00pm UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/11 "2023-03-29T15:00:13Z")

</div>

Thanks for all of your help! It got me pointed in the right direction.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [April 26, 2023, 3:00pm UTC](https://discuss.elastic.co/t/415-error-when-uploading-ndjson-to-kibana/328455/12 "2023-04-26T15:00:50Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
