Error reloading doctype when migrating from v12 to v13 (Sales Invoice)

Currently i’m testing the migration from V12 to V13 and i belive it already progresses pretty well. I got it to work with testdata, but when i restore a backup from the production system it failes, when migrating from V12 to V13. I guess it relates to custom modifications we did to the system, via a separate app. As far as i remember we did not customize any doctypes (git repo is clean on production system).

When i run bench migrate it spits out following exception trace:

Traceback (most recent call last):
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 104, in <module>
    main()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 19, in main
    click.Group(commands=commands)(prog_name='bench')
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/decorators.py", line 21, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/__init__.py", line 27, in _func
    ret = f(frappe._dict(ctx.obj), *args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/site.py", line 306, in migrate
    migrate(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/migrate.py", line 66, in migrate
    frappe.get_attr(fn)()
  File "/home/frappe/frappe-bench/apps/custom-app/custom-app/setup.py", line 584, in create_custom_fields
    frappe.reload_doc("accounts", "doctype", "sales_invoice")
  File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 958, in reload_doc
    return frappe.modules.reload_doc(module, dt, dn, force=force, reset_permissions=reset_permissions)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/utils.py", line 175, in reload_doc
    return import_files(module, dt, dn, force=force, reset_permissions=reset_permissions)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/import_file.py", line 48, in import_files
    return import_file(module, dt, dn, force=force, pre_process=pre_process,
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/import_file.py", line 54, in import_file
    ret = import_file_by_path(path, force, pre_process=pre_process, reset_permissions=reset_permissions)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/import_file.py", line 130, in import_file_by_path
    import_doc(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/import_file.py", line 213, in import_doc
    doc = frappe.get_doc(docdict)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 886, in get_doc
    doc = frappe.model.document.get_doc(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 75, in get_doc
    return controller(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 122, in __init__
    super(Document, self).__init__(kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 82, in __init__
    self.update(d)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 113, in update
    self.set(key, value)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 160, in set
    self.extend(key, value)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 206, in extend
    self.append(key, v)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 183, in append
    value = self._init_child(value, key)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 222, in _init_child
    value = get_controller(value["doctype"])(value)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 123, in __init__
    self.init_valid_columns()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 291, in init_valid_columns
    for key in self.get_valid_columns():
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 299, in get_valid_columns
    valid = get_table_columns(self.doctype)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/meta.py", line 49, in get_table_columns
    return frappe.db.get_table_columns(doctype)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 902, in get_table_columns
    raise self.TableMissingError('DocType', doctype)
pymysql.err.ProgrammingError: ('DocType', 'DocType Link')
Traceback (most recent call last):
  File "/usr/local/bin/bench", line 20, in <module>
    subprocess.check_call(
  File "/usr/local/lib/python3.9/subprocess.py", line 373, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/home/frappe/frappe-bench/env/bin/python', '/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py', 'frappe', 'migrate']' returned non-zero exit status 1.

The problem seems to be frappe.reload_doc("accounts", "doctype", "sales_invoice") all other doctypes can be reloaded, but Sales Invoice fails to reload. Also running bench reload-doctype "Sales Invoice" ends with the same issue:

Traceback (most recent call last):
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 104, in <module>
    main()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 19, in main
    click.Group(commands=commands)(prog_name='bench')
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/frappe/frappe-bench/env/lib/python3.9/site-packages/click/decorators.py", line 21, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/__init__.py", line 27, in _func
    ret = f(frappe._dict(ctx.obj), *args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/site.py", line 375, in reload_doctype
    frappe.reload_doctype(doctype, force=context.force)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 945, in reload_doctype
    reload_doc(scrub(db.get_value("DocType", doctype, "module")), "doctype", scrub(doctype),
  File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 958, in reload_doc
    return frappe.modules.reload_doc(module, dt, dn, force=force, reset_permissions=reset_permissions)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/utils.py", line 175, in reload_doc
    return import_files(module, dt, dn, force=force, reset_permissions=reset_permissions)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/import_file.py", line 48, in import_files
    return import_file(module, dt, dn, force=force, pre_process=pre_process,
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/import_file.py", line 54, in import_file
    ret = import_file_by_path(path, force, pre_process=pre_process, reset_permissions=reset_permissions)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/import_file.py", line 130, in import_file_by_path
    import_doc(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/import_file.py", line 213, in import_doc
    doc = frappe.get_doc(docdict)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 886, in get_doc
    doc = frappe.model.document.get_doc(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 75, in get_doc
    return controller(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 122, in __init__
    super(Document, self).__init__(kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 82, in __init__
    self.update(d)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 113, in update
    self.set(key, value)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 160, in set
    self.extend(key, value)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 206, in extend
    self.append(key, v)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 183, in append
    value = self._init_child(value, key)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 222, in _init_child
    value = get_controller(value["doctype"])(value)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 123, in __init__
    self.init_valid_columns()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 291, in init_valid_columns
    for key in self.get_valid_columns():
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/base_document.py", line 299, in get_valid_columns
    valid = get_table_columns(self.doctype)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/meta.py", line 49, in get_table_columns
    return frappe.db.get_table_columns(doctype)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 902, in get_table_columns
    raise self.TableMissingError('DocType', doctype)
pymysql.err.ProgrammingError: ('DocType', 'DocType Link')
Traceback (most recent call last):
  File "/usr/local/bin/bench", line 20, in <module>
    subprocess.check_call(
  File "/usr/local/lib/python3.9/subprocess.py", line 373, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/home/frappe/frappe-bench/env/bin/python', '/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py', 'frappe', 'reload-doctype', 'Sales Invoice']' returned non-zero exit status 1.

I’m currently lost on how to figure out what is causing the issue. DocType Link does not seem to be an doctype and i can not find this doctype to be used anywhere. Also googling for this issue didn’t give me a glue.

Can someone give me a hint how to find the issue or even a solution for this problem?

Thanks in advance.

Kevin

bench migrate —skip-failing

Thanks for sharing this idea. If i understand -skip-failing correctly it just continues with the migration of the next app when the migration code of an app fails. But failing is caused due to an exception inside the migration code. Which then causes the following migration code not to be run. Rather then skipping this part, i wish to find and fix the root cause of the issue. If i am right, the issue is caused by a customisation/fixture of the doctype Sales Invoice but i don’t know how to figure out which one is causing the error, as reload doesn’t show any hint on what is wrong.

I added some logging code to def get_valid_columns(self): in frappe/frappe/model/base_document.py. It seems to be the following entry, which causes the problem.

{'doctype': 'DocType Link', 'name': None, '_default_new_docs': {}, 'flags': {}, 'group': 'Reference', 'link_doctype': 'POS Invoice', 'link_fieldname': 'consolidated_invoice', 'dont_update_if_missing': [], 'owner': None, 'creation': None, 'modified': None, 'modified_by': None, 'parent': None, 'parentfield': None, 'parenttype': None, 'idx': 0, 'docstatus': 0}

I searched the frappe sourcecode and found the doctype DocType Link but why doesn’t it find this entry?