Call to route in Kibana plugin and then to external REST API

I am creating a visualization plugin for extracting all filters that is applied to the current dashboard and submit it to an external rest API. It is working effortlessly in my local development environment (ES & Kibana 7.9.2), but as soon as I install the plugin on my server machine, I get a 404 - Not Found error when I try to make a call to my route.

As far as I see the call is not even arriving at the route. The error is for a post at the path for the defined route.

Here is a screenshot from the DevTools:


Here is the call that I make in my plugin to access my defined route, which is located under <plugin-root>/public/plugin_controller.tsx:

    url: '/api/dashboardfilterexporter/submit',
    type: 'POST',
    cache: false,
    contentType: 'application/json',
    data: requestData,
    success: function (result) {'Success');
    error: function (error) {

And this is the defined route that should get called, located under <plugin-root>/server/routes.ts:
      path: '/api/dashboardfilterexporter/submit',
      validate: {
        body: schema.object({
          url: schema.string(),
          query: schema.string()
    async (context: RequestHandlerContext, request: KibanaRequest, response) => {
      const query = JSON.parse(request.body.query);
      const url = new URL(request.body.url);

      var options = {
        protocol: url.protocol,
        host: url.hostname,
        port: url.port,
        path: url.pathname,
        method: 'POST',
        headers: {
          'Content-Type': 'text/plain'

      return new Promise((resolve, reject) => {
        const req = http.request(options, (res) => {
          res.on('data', (d) => {

        req.on('error', (e) => {

      }).catch(err => {
        if (err.status == 404) {
          return response.notFound(err);
        } else {
          return response.badRequest(err);

It works locally, so what I expect is that there is something blocking the call somehow, but I though as long as it is within Kibana, it should not be a problem?


not sure if this is related, but in dev-mode, Kibana will run behind a proxy at a temporary generated path.

e.g. it would look somerthing like http://localhost:5601/zpf/app/maps/map.

the zpf path is injected only at dev-time and you will not see in your server-deploment.

Make sure your api-paths are not creating an extra hop that will not be necessary when your Kibana is deployed.

Thanks for the pointer, I changed the ajax call to the path /api/dashboardfilterexporter/submit but the error appears to be the same.

How are you packaging the plugin for production? We had a few issues with our 3rd plugin building tools in 7.9 that were only fixed in 7.10, see

I suspect that the plugin is simply not recognized when installed on the server. If you open the plugin's archive, do you have the kibana.json file inside it? Would you try with a 7.10 version (when packaging the plugin, not only the server's version)

I run my development environment in Windows. I copy the content of the plugin's folder to my server (running Ubuntu) and there I zip the content into a zip file (kibana/pluginname).
The plugin is recognized, I see it listed among my visualizations, and I am able to create a visualization with it. The issue is that when I press the button in my visualization (which collects the filters and packages them), I get the above error. It appears to be that the call does not find the route. Do I need so set any headers or something for when I make internal calls to a route, such as kbn-xsrf?

Lacking the kbn-xsrf header would not cause a 404.

Are you using a basePath on your production server, or are you testing under a different space that default ? If so, using $.ajax would not append the current basePath, causing the call to go to /api/XXX instead of {basePath}/api/XXX.

If that's the case, the preferred solution is to use the http core service instead ( in your case), but you could also do something like

    url: http.basePath.preprend('/api/dashboardfilterexporter/submit')

I implemented the http.basePath.prepend( thinking it can't hurt to try it but it was not the error in the end. There is still an issue, but it is that the router cannot find my external endpoint that I want to call. The confusion happened because I forward the error that the router gets from its call, so that it looks as if ajax's call to the route returns a Not found.

In the end the route works, but I am unable to reach my external target. My Kibana server is located on a server, and I am connecting to Kibana through the browser of my local computer. I think we are in the same network (but over VPN). The external endpoint is located on my local computer.

If my configured url is 'http://localhost:1234/endpoint/post' I assume that the route finds it correctly? Or do I have to configure my url to point to my local computer, the way that the server "sees" my computer?

The other possibility is that the call is blocked by CSP maybe?

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