Odoo Node: Intermittant "Stack NodeApiError: 'Request' object has no attribute 'session'

Describe the problem/error/question

Since 1.0.1 and annoyingly intermittantly, Odoo Requests return a failure. Setting “Retry” > 1 increases chances of workflow succeeding, so the data being retrieved/pushed is not incorrect.

What is the error message (if any)?

Stack

NodeApiError: 'Request' object has no attribute 'session'
    at Object.odooGetUserID (/usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base/dist/nodes/Odoo/GenericFunctions.js:292:15)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at Object.execute (/usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base/dist/nodes/Odoo/Odoo.node.js:258:24)
    at Workflow.runNode (/usr/local/lib/node_modules/n8n/node_modules/n8n-workflow/dist/Workflow.js:658:19)
    at /usr/local/lib/node_modules/n8n/node_modules/n8n-core/dist/WorkflowExecute.js:631:53

In one of the examples below, you can see that the previous Odoo nodes had run sucessfully many times previously. This is similar behaviour to the postgresql node, recently fixed on fix(Postgres Node): Connection pool of the database object has been destroyed by michael-radency · Pull Request #7074 · n8n-io/n8n · GitHub

My odoo server seems to be working as expected, and odoo tech support ( :wink: as always) suggest it is a problem on the API access side.

Please share your workflow

2 examples of many:

Or:

Share the output returned by the last node

Information on your n8n setup

  • n8n version: 1.4.1
  • Database (default: SQLite):
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker):
  • Operating system: Ubuntu, self host.

Hi @Luke_Austin, I am sorry you’re having trouble. I was not able to reproduce it on my side, but tbh I don’t really understand Odoo in the first place :see_no_evil:

This looks like n8n is trying to read a session value which isn’t always present. @marcus do you by any chance know whether this is something node-specific and in which circumstances such an error might come up?

@MutedJam @marcus

Thanks! Yeah, it’s the intermittant nature that confuses me. It it fails, and i push the same item, it invariably goes through in testing. “Retry” catches most in production, with sometimes up to 5k items to process, but it worries me nonetheless.

I initially though it was the same as the Postgresql bug, because it started at the same time, odoo is built on postgresql, and seemed to have the same route. That bug turned out to be duplication in code and loss of the session identifier (as far as I understand it) on the n8n side and i wonder whether there may be something similar going on from the migration to 1.x

Hi @Luke_Austin,
I couldn’t reproduce the issue and I don’t see any session value being processed on the n8n node side that could fail. I will have to investigate further to find out more.

Also this shouldn’t be related to the mentioned Postgresql issue at all, because the Odoo node does not depend on postgres.

@marcus - some more information

From my odoo server log:

2023-09-19 10:40:18,318 1703 ERROR btx odoo.http: Exception during request handling.
Traceback (most recent call last):
  File "/opt/odoo/odoo-server/odoo/http.py", line 1998, in __call__
    response = request._serve_db()
  File "/opt/odoo/odoo-server/odoo/http.py", line 1584, in _serve_db
    return service_model.retrying(self._serve_ir_http, self.env)
  File "/opt/odoo/odoo-server/odoo/service/model.py", line 133, in retrying
    result = func()
  File "/opt/odoo/odoo-server/odoo/http.py", line 1611, in _serve_ir_http
    response = self.dispatcher.dispatch(rule.endpoint, args)
  File "/opt/odoo/odoo-server/odoo/http.py", line 1815, in dispatch
    result = self.request.registry['ir.http']._dispatch(endpoint)
  File "/opt/odoo/odoo-server/addons/website/models/ir_http.py", line 237, in _dispatch
    response = super()._dispatch(endpoint)
  File "/opt/odoo/odoo-server/odoo/addons/base/models/ir_http.py", line 154, in _dispatch
    result = endpoint(**request.params)
  File "/opt/odoo/odoo-server/odoo/http.py", line 697, in route_wrapper
    result = endpoint(self, *args, **params_ok)
  File "/opt/odoo/odoo-server/odoo/addons/base/controllers/rpc.py", line 158, in jsonrpc
    return dispatch_rpc(service, method, args)
  File "/opt/odoo/odoo-server/odoo/http.py", line 366, in dispatch_rpc
    return dispatch(method, params)
  File "/opt/odoo/odoo-server/odoo/service/common.py", line 56, in dispatch
    return g[exp_method_name](*params)
  File "/opt/odoo/odoo-server/odoo/service/common.py", line 20, in exp_login
    return exp_authenticate(db, login, password, None)
  File "/opt/odoo/odoo-server/odoo/service/common.py", line 27, in exp_authenticate
    return res_users.authenticate(db, login, password, {**user_agent_env, 'interactive': False})
  File "/opt/odoo/odoo-server/addons/website/models/res_users.py", line 76, in authenticate
    uid = super(ResUsers, cls).authenticate(db, login, password, user_agent_env)
  File "/opt/odoo/odoo-server/odoo/addons/base/models/res_users.py", line 802, in authenticate
    uid = cls._login(db, login, password, user_agent_env=user_agent_env)
  File "/opt/odoo/odoo-server/odoo/addons/base/models/res_users.py", line 773, in _login
    user = self.search(self._get_login_domain(login), order=self._get_login_order(), limit=1)
  File "/opt/odoo/odoo-server/addons/website/models/res_users.py", line 41, in _get_login_domain
    website = self.env['website'].get_current_website()
  File "/opt/odoo/odoo-server/addons/website/models/website.py", line 952, in get_current_website
    if request and request.session.get('force_website_id'):
AttributeError: 'Request' object has no attribute 'session'

Using this demo flow:

My Odoo Server looks like this:

I wonder whether n8n is closing the sessions after each query, and then eventually getting booted because there are no available postgres workers left, thus no “session”.

A sudo systemctl restart postgresql seems to give a blank slate, but I’d rather not run that everytime a node fails!

@marcus

A bit more research: The problem is at least partly occuring here:

# ----------------------------------------------------------
    # Utilities
    # ----------------------------------------------------------

    @api.model
    def get_current_website(self, fallback=True):
        """ The current website is returned in the following order:
        - the website forced in session `force_website_id`
        - the website set in context
        - (if frontend or fallback) the website matching the request's "domain"
        - arbitrary the first website found in the database if `fallback` is set
          to `True`
        - empty browse record
        """
        is_frontend_request = request and getattr(request, 'is_frontend', False)
        if request and request.session.get('force_website_id'):
            website_id = self.browse(request.session['force_website_id']).exists()
            if not website_id:
                # Don't crash is session website got deleted
                request.session.pop('force_website_id')
            else:
                return website_id

        website_id = self.env.context.get('website_id')
        if website_id:
            return self.browse(website_id)

        if not is_frontend_request and not fallback:
            # It's important than backend requests with no fallback requested
            # don't go through
            return self.browse(False)

        # Reaching this point means that:
        # - We didn't find a website in the session or in the context.
        # - And we are either:
        #   - in a frontend context
        #   - in a backend context (or early in the dispatch stack) and a
        #     fallback website is requested.
        # We will now try to find a website matching the request host/domain (if
        # there is one on request) or return a random one.

It seems to be a problem with odoo’s multiple website handling - which i’ve now fallen foul of as we are hosting two websites on my server - Is there a way to set the website_id on the n8n side? I imagine the credentials manager would be the best place for it?

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