I have successfully programmed a Joomla 4/5 API to generate an API web service. There is a kind of weird bug uploading files though, because it basically works on localhost - but on the live system I get the following error:

2023-11-07T20:10:12+00:00   CRITICAL   error   Uncaught Throwable of type Joomla\CMS\Router\Exception\RouteNotFoundException thrown with message "Page not found". Stack trace: #0 [ROOT]/libraries/src/Application/SiteApplication.php(754): Joomla\CMS\Router\Router->parse()
#1 [ROOT]/libraries/src/Application/SiteApplication.php(244): Joomla\CMS\Application\SiteApplication->route()
#2 [ROOT]/libraries/src/Application/CMSApplication.php(306): Joomla\CMS\Application\SiteApplication->doExecute()
#3 [ROOT]/includes/app.php(58): Joomla\CMS\Application\CMSApplication->execute()
#4 [ROOT]/index.php(32): require_once('...')
#5 {main}

It seems that Joomla cannot find the API endpoint, when called from JavaScript Node.js (Netlify). It does not reach the API controller. Joomla 4 does not log any error message. Joomla 5 at least prints the above message. -

The registerRoutes() of the Plugin looks like this:

 $routes = [
   new Route(
     ['id' => '(\d+)']

The defined Route can be successfully called on localhost or by using Postman (with "multipart/form-data") via this URL: https://myjoomlaapiserver.com/api/v1/...fileupload/1

On the JavaScript Side (Vue 3/ Nuxt 3) the code calling the endpoint generates a file Blob and sends it to the Joomla API.

const results = await $fetch(
     method: "POST",
     body: newFormData,
     headers: {
       // "Content-Type": "multipart/form-data",
       'Accept': '*/*', //! Ohne gibt's einen 406 Error
        Authorization: `Bearer ${config.BEARER}`,

More details on the Vue client here https://stackoverflow.com/questions/77232507/file-upload-through-pinia-store-and-the-nuxt-3-server-api

Any ideas why this works on localhost but not on Joomla 4 or Joomla 5? How to get better debugging info on the Joomla side?

  • What is the full endpoint URL? Is your live site installed in a subdirectory?
    – Sharky
    Commented Nov 8, 2023 at 6:09
  • The Joomla API endpoint URL is on another Server. It works with Postman ("multipart/form-data").
    – cappu
    Commented Nov 8, 2023 at 11:48
  • Added some code to the question above
    – cappu
    Commented Nov 8, 2023 at 14:58
  • Can you try changing URL so it includes index.php, e.g. https://myjoomlaapiserver.com/api/index.php/v1/...?
    – Sharky
    Commented Nov 8, 2023 at 16:24
  • 1
    I'm almost certain server configuration needs to be updated to allow api/index.php handle SEF URLs. See Joomla documentation for Nginx docs.joomla.org/Nginx. For Apache, inspect the htaccess.txt that ships with Joomla (note it has an error which prevents API from working when J! is installed in a subdirectory).
    – Sharky
    Commented Nov 9, 2023 at 18:19

1 Answer 1


After a lot of research I have finally found the cause of the error.

On the Joomla side, you need to set the CORS parameter Access-Control-Allow-Headers to Content-Type,X-Joomla-Token,Authorization,Accept in the Joomla main configuration!

The main cause of the problem is on the server side of the Nuxt 3 application: Netlify blocks file processing and redirection to Joomla, because it mainly a service to server static content. - The solution is to communicate the file upload from the Nuxt 3 / Vue 3 web app client/browser directly.

const url = `${config.public.fileServerUrl}/api/v1/fileuploadroute`;
const results = await useFetch(
       method: "POST",
       body: form_data,
       headers: {
          // 'Content-Type': 'multipart/form-data',  // DISABLE
          'Accept': '*/*', //! Ohne gibt's einen 406 Error
          Authorization: `Bearer ${config.public.fileBearerToken}`,

As the Joomla API token is exposed to the web application client, I generated an additional one just for file uploads. - Options to hide the API token from the client could be writing a Netlify function or using Vercel. I haven't tried both yet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.