V14 error sending emails with 'Attach Document Print'

In v14, we’ve started seeing email messages getting stuck in the Email Queue. When you send an email from a document and use the ‘Attach Document Print’ option, the message sits in the queue as ‘Not Sent’ for several minutes until eventually, it goes into error state and the below message appears in the Error Log. I’ve confirmed that it occurs for multiple doctypes and both stock and custom print formats.

I found this thread where a somewhat similar issue was reported. My environment is containerized, as well. Per the resolution on that thread, I’ve checked that the assets directory is mounted. I can exec into the gunicorn container. There are files in the assets/ dir and it’s writeable to the exec user. I’m not sure if there’s anything else there to check?

Edit: One other quirk worth mentioning: If I go into the message in the queue and hit ‘send now’, it sends successfully without complaint.

Edit #2: While my assets directory is populated in the gunicorn container, it’s empty in the worker container so this may be the problem, after all.

Edit #3: Empty assets directory in worker containers seems to be normal. Back to the drawing board.

Frappe: v14.8.0
ERPNext: 14.1.2

Thanks in advance for any help!

—CUT—
File “/home/frappe/frappe-bench/apps/frappe/frappe/email/doctype/email_queue/email_queue.py”, line 134, in send
message = ctx.build_message(recipient.recipient)
File “/home/frappe/frappe-bench/apps/frappe/frappe/email/doctype/email_queue/email_queue.py”, line 293, in build_message
message = self.include_attachments(message)
File “/home/frappe/frappe-bench/apps/frappe/frappe/email/doctype/email_queue/email_queue.py”, line 356, in include_attachments
print_format_file = frappe.attach_print(**attachment)
File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 2076, in attach_print
content = get_print(doctype, name, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 2026, in get_print
html = get_response_content(“printview”)
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/serve.py”, line 33, in get_response_content
response = get_response(path, http_status_code)
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/serve.py”, line 27, in get_response
response = ErrorPage(exception=e).render()
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py”, line 78, in render
html = self.get_html()
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/utils.py”, line 510, in cache_html_decorator
html = func(*args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py”, line 95, in get_html
html = self.render_template()
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py”, line 232, in render_template
html = frappe.render_template(self.source, self.context, safe_render=safe_render)
File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja.py”, line 85, in render_template
return get_jenv().from_string(template).render(context)
File “/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/environment.py”, line 1301, in render
self.environment.handle_exception()
File “/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/environment.py”, line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File “”, line 1, in top-level template code
File “/home/frappe/frappe-bench/apps/frappe/frappe/templates/web.html”, line 1, in top-level template code
{% extends base_template_path %}
File “/home/frappe/frappe-bench/apps/frappe/frappe/templates/base.html”, line 25, in top-level template code
{%- block head -%}
File “/home/frappe/frappe-bench/apps/frappe/frappe/templates/base.html”, line 33, in block ‘head’
{{ include_style(‘website.bundle.css’) }}
File “/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/sandbox.py”, line 393, in call
return __context.call(__obj, *args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja_globals.py”, line 118, in include_style
path = bundled_asset(path)
File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja_globals.py”, line 136, in bundled_asset
path = bundled_assets.get(path) or path

The most specific error I can find:

20:32:49 home-frappe-frappe-bench:short: Job OK (7cdd9955-71fb-4432-9bcd-2672ff4d70b0)
20:32:49 Result is kept for 600 seconds
20:32:49 home-frappe-frappe-bench:short: frappe.utils.background_jobs.execute_job(event=‘all’, is_async=True, job_name=‘pull_from_email_account|Notifications’, kwargs={‘email_account’: ‘Notifications’}, method=<function pull_from_email_account at 0x7f4dea45d360>, site=‘xxx.xxxxx.xxx’, user=‘Administrator’) (cacdb308-ec6a-4010-bb1b-feb75733c199)
/home/frappe/frappe-bench/apps/frappe/frappe/database/query.py:197: UserWarning: The ‘filters_config’ hook used to add custom operators is not yet implemented in frappe.db.query engine. Use db_query (frappe.get_list) instead.
warn(
20:32:50 home-frappe-frappe-bench:short: Job OK (cacdb308-ec6a-4010-bb1b-feb75733c199)
20:32:50 Result is kept for 600 seconds
20:32:50 home-frappe-frappe-bench:short: frappe.utils.background_jobs.execute_job(event=None, is_async=True, job_name=‘<function send_mail at 0x7f4dea020d30>’, kwargs={‘email_queue_name’: ‘15ecb36ca0’, ‘is_background_task’: True}, method=<function send_mail at 0x7f4dea020d30>, site=‘xxx.xxxxxx.xxx’, user=‘Administrator’) (e35bd878-8762-4171-86fa-31bd3bde2a49)
/home/frappe/frappe-bench/apps/frappe/frappe/database/query.py:197: UserWarning: The ‘filters_config’ hook used to add custom operators is not yet implemented in frappe.db.query engine. Use db_query (frappe.get_list) instead.
warn(
20:32:52 Traceback (most recent call last):
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/serve.py”, line 18, in get_response
response = renderer_instance.render()
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py”, line 78, in render
html = self.get_html()
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/utils.py”, line 510, in cache_html_decorator
html = func(*args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py”, line 95, in get_html
html = self.render_template()
File “/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py”, line 232, in render_template
html = frappe.render_template(self.source, self.context, safe_render=safe_render)
File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja.py”, line 85, in render_template
return get_jenv().from_string(template).render(context)
File “/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/environment.py”, line 1301, in render
self.environment.handle_exception()
File “/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/environment.py”, line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File “”, line 8, in top-level template code
File “/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/sandbox.py”, line 393, in call
return __context.call(__obj, *args, **kwargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja_globals.py”, line 118, in include_style
path = bundled_asset(path)
File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja_globals.py”, line 136, in bundled_asset
path = bundled_assets.get(path) or path
AttributeError: ‘NoneType’ object has no attribute ‘get’

Same issue here.

Traceback (most recent call last):
  File "apps/frappe/frappe/website/serve.py", line 18, in get_response
    response = renderer_instance.render()
  File "apps/frappe/frappe/website/page_renderers/print_page.py", line 24, in render
    return super().render()
  File "apps/frappe/frappe/website/page_renderers/template_page.py", line 78, in render
    html = self.get_html()
  File "apps/frappe/frappe/website/utils.py", line 510, in cache_html_decorator
    html = func(*args, **kwargs)
  File "apps/frappe/frappe/website/page_renderers/template_page.py", line 89, in get_html
    self.update_context()
  File "apps/frappe/frappe/website/page_renderers/template_page.py", line 157, in update_context
    data = self.run_pymodule_method("get_context")
  File "apps/frappe/frappe/website/page_renderers/template_page.py", line 219, in run_pymodule_method
    return method(self.context)
  File "apps/frappe/frappe/www/printview.py", line 51, in get_context
    body = get_rendered_template(
  File "apps/frappe/frappe/www/printview.py", line 153, in get_rendered_template
    format_data_map[df.get("fieldname")] = df
AttributeError: 'str' object has no attribute 'get'

Installed Apps

ERPNext: v14.3.0 (version-14)

Frappe Framework: v14.11.1 (version-14)

Payments: v0.0.1 (develop)

1 Like

Wondering if anyone else is having this issue with V14? Still happening for me…
ERPNext: v14.9.0 (version-14)
Frappe Framework: v14.17.1 (version-14)

I heard the spirit of John Clark asking me what I had learnt so far to try to fix this issue myself. So please excuse the seemingly rambling style of this post as I have been digging into this error and I have found out the following:

  • I have a print format for my Sales Invoice that I made using the new print format builder in v14
  • PDF printing works fine.
  • Web display of the print format failes with the error mentioned above.
  • The file in question is the frappe core file printview.py located at frappe/frappe/www/printview.py
  • The function that is in question is called “get_rendered_template” and the sub function that is producing the error is :
def get_template_from_string():
      return jenv.from_string(get_print_format(doc.doctype, print_format))

    if print_format.custom_format:
      template = get_template_from_string()

    elif print_format.format_data:
      # set format data
      format_data = json.loads(print_format.format_data)
      for df in format_data:
        format_data_map[df.get("fieldname")] = df
        if "visible_columns" in df:
          for _df in df.get("visible_columns"):
            format_data_map[_df.get("fieldname")] = _df

      doc.format_data_map = format_data_map

      template = "standard"
  • Now, narrowing down further, the error is produced while iterating through the python dictionary returned after running json.loads(print_format.format_data). From the EPRNext error log list I can see the value of format_data as a python dictionary:
 format_data = {'header': 'SALES INVOICE', 'sections': [{'label': '', 'columns': [{'label': '', 'fields': [{'label': 'Custom HTML', 'fieldname': 'custom_html', 'fieldtype': 'HTML', 'html': '<p style="line-height: 2em;">\n    Invoice Number: {{ doc.name }}<br>\n    Invoice Date: {{ doc.get_formatted(\'posting_date\') }}<br>\n    Invoice Due Date: {{ doc.get_formatted(\'due_date\') }}\n</p>'}]}]}, {'label': '', 'columns': [{'label': '', 'fields': [{'label': 'Divider', 'fieldname': 'divider', 'fieldtype': 'Divider'}]}]}, {'label': '', 'columns': [{'label': '', 'fields': [{'label': 'Customer Name', 'fieldname': 'customer_name', 'fieldtype': 'Small Text'}, {'label': 'Address', 'fieldname': 'address_display', 'fieldtype': 'Small Text'}]}, {'label': '', 'fields': [{'label': 'Contact', 'fieldname': 'contact_display', 'fieldtype': 'Small Text'}, {'label': 'Mobile No', 'fieldname': 'contact_mobile', 'fieldtype': 'Small Text'}]}], 'has_fields': True}, {'label': '', 'columns': [{'label': '', 'fields': [{'label':...
  • df is the ‘key’ in the for loop and the first iteration of the key is ‘header’ as I found returned in the data dump of the ERPNext error log list:
      format_data_map = {}
      get_template_from_string = <function get_rendered_template.<locals>.get_template_from_string at 0x7f24c70d8940>
      df = 'header'
      doc = <SalesInvoice: INV-00622-1 docstatus=1>
      jenv = <jinja2.sandbox.SandboxedEnvironment object at 0x7f24c5c6ad40>
      print_format = <PrintFormat: Sales Invoice - Little Bunyip>
builtins.AttributeError: 'str' object has no attribute 'get'
  • The value of df in the first iteration through the variable format_data is the string 'header'. We can’t use the function .get on a string and the error is thrown.

Am I on the right track?

Same problem, did you find the solution?

I too, experiencing the same issues. Anyone with any hints what to try or where to look.

The error message that pops up contains the following:
“/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja_globals.py” “line 136” “AttributeError” “NoneType” “object has no attribute”

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/gunicorn/workers/gthread.py", line 271, in handle
    keepalive = self.handle_request(req, conn)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/gunicorn/workers/gthread.py", line 323, in handle_request
    respiter = self.wsgi(environ, resp.start_response)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/werkzeug/local.py", line 237, in application
    return ClosingIterator(app(environ, start_response), self.cleanup)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/werkzeug/wrappers/request.py", line 187, in application
    resp = f(*args[:-2] + (request,))
  File "/home/frappe/frappe-bench/apps/frappe/frappe/app.py", line 87, in application
    response = handle_exception(e)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/app.py", line 324, in handle_exception
    response = get_response("message", http_status_code=http_status_code)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/website/serve.py", line 27, in get_response
    response = ErrorPage(exception=e).render()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py", line 78, in render
    html = self.get_html()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/website/utils.py", line 510, in cache_html_decorator
    html = func(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py", line 95, in get_html
    html = self.render_template()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/website/page_renderers/template_page.py", line 232, in render_template
    html = frappe.render_template(self.source, self.context, safe_render=safe_render)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja.py", line 85, in render_template
    return get_jenv().from_string(template).render(context)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "<template>", line 1, in top-level template code
  File "/home/frappe/frappe-bench/apps/frappe/frappe/templates/web.html", line 1, in top-level template code
    {% extends base_template_path %}
  File "/home/frappe/frappe-bench/apps/frappe/frappe/templates/base.html", line 25, in top-level template code
    {%- block head -%}
  File "/home/frappe/frappe-bench/apps/frappe/frappe/templates/base.html", line 26, in block 'head'
    {% include "templates/includes/head.html" %}
  File "/home/frappe/frappe-bench/apps/frappe/frappe/templates/includes/head.html", line 8, in top-level template code
    {{ include_style('website.bundle.css') }}
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/jinja2/sandbox.py", line 393, in call
    return __context.call(__obj, *args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja_globals.py", line 118, in include_style
    path = bundled_asset(path)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/jinja_globals.py", line 136, in bundled_asset
    path = bundled_assets.get(path) or path
AttributeError: 'NoneType' object has no attribute 'get'

Was there a solution to this? I am also getting the below error while printing as well as in the email attachment.

AttributeError: ‘str’ object has no attribute ‘get’

Yeap, same here. Any one else lucky?

i’am Facing same issue

I read somewhere this is related to the new print format builder. Recommended to avoid it, that it may be removed from v15.

Same issue here with the new print format builder.

Preview works fine in app, but email crashes.

Traceback with variables (most recent call last):
  File "apps/frappe/frappe/website/serve.py", line 18, in get_response
    response = renderer_instance.render()
      path = '/Vessel Action Package Run/Emballer - S23-071 - 546.0 x Caisse 24 x 473 ml - 12 juil. 11:10'
      http_status_code = 200
      response = None
      endpoint = 'Vessel Action Package Run/Emballer - S23-071 - 546.0 x Caisse 24 x 473 ml - 12 juil. 11:10'
      path_resolver = <frappe.website.path_resolver.PathResolver object at 0x7f3a2d8f09d0>
      renderer_instance = <frappe.website.page_renderers.print_page.PrintPage object at 0x7f3a2d426a70>
      e = AttributeError("'str' object has no attribute 'get'")
  File "apps/frappe/frappe/website/page_renderers/print_page.py", line 24, in render
    return super().render()
      self = <frappe.website.page_renderers.print_page.PrintPage object at 0x7f3a2d426a70>
      parts = ['Vessel Action Package Run', 'Emballer - S23-071 - 546.0 x Caisse 24 x 473 ml - 12 juil. 11:10']
      __class__ = <class 'frappe.website.page_renderers.print_page.PrintPage'>
  File "apps/frappe/frappe/website/page_renderers/template_page.py", line 84, in render
    html = self.get_html()
      self = <frappe.website.page_renderers.print_page.PrintPage object at 0x7f3a2d426a70>
  File "apps/frappe/frappe/website/utils.py", line 510, in cache_html_decorator
    html = func(*args, **kwargs)
      args = (<frappe.website.page_renderers.print_page.PrintPage object at 0x7f3a2d426a70>,)
      kwargs = {}
      html = None
      page_cache = None
      func = <function TemplatePage.get_html at 0x7f3a2e4da560>
  File "apps/frappe/frappe/website/page_renderers/template_page.py", line 95, in get_html
    self.update_context()
      self = <frappe.website.page_renderers.print_page.PrintPage object at 0x7f3a2d426a70>
  File "apps/frappe/frappe/website/page_renderers/template_page.py", line 163, in update_context
    data = self.run_pymodule_method("get_context")
      self = <frappe.website.page_renderers.print_page.PrintPage object at 0x7f3a2d426a70>
  File "apps/frappe/frappe/website/page_renderers/template_page.py", line 225, in run_pymodule_method
    return method(self.context)
      self = <frappe.website.page_renderers.print_page.PrintPage object at 0x7f3a2d426a70>
      method_name = 'get_context'
      inspect = <module 'inspect' from '/usr/lib/python3.10/inspect.py'>
      method = <function get_context at 0x7f3a2e365ea0>
  File "apps/frappe/frappe/www/printview.py", line 52, in get_context
    body = get_rendered_template(
      context = {'top_bar_items': [<TopBarItem: 35c322ab70 parent=Website Settings>, <TopBarItem: 3f7c8540b6 parent=Website Settings>, <TopBarItem: 86db780dec parent=Website Settings>], 'footer_items': [], 'post_login': [{'label': 'Mon Compte', 'url': '/me'}, {'label': 'Log out', 'url': '/?cmd=web_logout'}], 'brand_html': '', 'copyright': '', 'facebook_share': 0, 'google_plus_one': 0, 'twitter_share': 0, 'linked_in_share': 0, 'disable_signup': 0, 'url': '', 'encoded_title': '', 'web_include_js': ['website_script.js', 'erpnext-web.bundle.js'], 'web_include_css': ['erpnext-web.bundle.css'], 'favicon': '/assets/erpnext/images/erpnext-favicon.svg', 'splash_image': '/assets/erpnext/images/erpnext-logo.svg', 'theme': <WebsiteTheme: Standard>, 'hide_login': 0, 'read_only_mode': False, 'boot': {'sysdefaults': {'float_precision': 3, 'date_format': 'yyyy-mm-dd', 'time_format': 'HH:mm:ss'}, 'time_zone': {'system': 'America/Toronto', 'user': 'America...
      doc = <VesselActionPackageRun: Emballer - S23-071 - 546.0 x Caisse 24 x 473 ml - 12 juil. 11:10 docstatus=1>
      settings = None
      letterhead = None
      meta = <Meta: Vessel Action Package Run>
      print_format = <PrintFormat: Emballage>
      print_style = None
  File "apps/frappe/frappe/www/printview.py", line 154, in get_rendered_template
    format_data_map[df.get("fieldname")] = df
      name = None
      meta = <Meta: Vessel Action Package Run>
      no_letterhead = False
      letterhead = None
      trigger_print = None
      settings = None
      print_settings = {'name': 'Print Settings', 'owner': 'Administrator', 'creation': '2022-01-24 19:40:33.391629', 'modified': '2023-01-19 13:18:13.707169', 'modified_by': 'Administrator', 'docstatus': 0, 'idx': '0', 'send_print_as_pdf': 1, 'repeat_header_footer': 1, 'pdf_page_size': 'A4', 'pdf_page_height': 0.0, 'pdf_page_width': 0.0, 'with_letterhead': 1, 'compact_item_print': 1, 'print_uom_after_quantity': 0, 'allow_print_for_draft': 1, 'add_draft_heading': 1, 'allow_page_break_inside_tables': 0, 'allow_print_for_cancelled': 0, 'print_taxes_with_zero_amount': 0, 'enable_print_server': 0, 'enable_raw_printing': 0, 'print_style': 'Modern', 'font': 'Default', 'font_size': 0.0, 'doctype': 'Print Settings'}
      format_data = 
      format_data_map = {}
      get_template_from_string = <function get_rendered_template.<locals>.get_template_from_string at 0x7f3a2e9cc5e0>
      df = 'header'
      doc = <VesselActionPackageRun: Emballer - S23-071 - 546.0 x Caisse 24 x 473 ml - 12 juil. 11:10 docstatus=1>
      jenv = <jinja2.sandbox.SandboxedEnvironment object at 0x7f3a2d6c5f00>
      print_format = <PrintFormat: Emballage>
builtins.AttributeError: 'str' object has no attribute 'get'