frappe@cb8d870af36d:~/frappe-bench$ bench --site shirtful-erpnext.amicaldo.net install-app hrms
App erpnext already installed
Installing hrms...
Updating DocTypes for hrms : [========================================] 100%
Setting up Frappe HR...
Patching Existing Data...
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 177, in <module>
main()
File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 77, in main
FrappeClickWrapper(click.Group, handle_exception)(commands=commands)(prog_name="bench")
File "/home/frappe/frappe-bench/env/lib/python3.14/site-packages/click/core.py", line 1485, in __call__
return self.main(*args, **kwargs)
File "/home/frappe/frappe-bench/env/lib/python3.14/site-packages/click/core.py", line 1406, in main
rv = self.invoke(ctx)
File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 48, in invoke
return super().invoke(ctx)
File "/home/frappe/frappe-bench/env/lib/python3.14/site-packages/click/core.py", line 1873, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 48, in invoke
return super().invoke(ctx)
File "/home/frappe/frappe-bench/env/lib/python3.14/site-packages/click/core.py", line 1873, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/frappe/frappe-bench/env/lib/python3.14/site-packages/click/core.py", line 1269, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/frappe/frappe-bench/env/lib/python3.14/site-packages/click/core.py", line 824, in invoke
return callback(*args, **kwargs)
File "/home/frappe/frappe-bench/env/lib/python3.14/site-packages/click/decorators.py", line 34, in new_func
return f(get_current_context(), *args, **kwargs)
File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/__init__.py", line 28, in _func
ret = f(ctx.obj, *args, **kwargs)
File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/site.py", line 522, in install_app
_install_app(app, verbose=context.verbose, force=force)
File "/home/frappe/frappe-bench/apps/frappe/frappe/installer.py", line 333, in install_app
frappe.get_attr(after_install)()
File "/home/frappe/frappe-bench/apps/hrms/hrms/install.py", line 9, in after_install
setup()
File "/home/frappe/frappe-bench/apps/hrms/hrms/setup.py", line 22, in after_install
run_post_install_patches()
File "/home/frappe/frappe-bench/apps/hrms/hrms/setup.py", line 578, in run_post_install_patches
frappe.get_attr(f"hrms.patches.post_install.{patch_name}.execute")()
File "/home/frappe/frappe-bench/apps/hrms/hrms/patches/post_install/move_payroll_setting_separately_from_hr_settings.py", line 9, in execute
data = frappe.db.sql(
File "/home/frappe/frappe-bench/apps/frappe/frappe/database/postgres/database.py", line 234, in sql
return super().sql(modify_query(query), modify_values(values), *args, **kwargs)
File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 294, in sql
traceback.print_stack()
Error in query:
column "HR Settings" does not exist
LINE 4: doctype = "HR Settings"
^
Installation for Frappe HR app failed due to an error. Please try re-installing the app or report the issue on https://github.com/frappe/hrms/issues/new if not resolved.
An error occurred while installing hrms: column "HR Settings" does not exist
LINE 4: doctype = "HR Settings"
^
Traceback with variables (most recent call last):
File "apps/frappe/frappe/commands/site.py", line 522, in install_app
_install_app(app, verbose=context.verbose, force=force)
context = CliCtxObj(force=False, profile=False, sites=['shirtful-erpnext.amicaldo.net'], verbose=False)
apps = ('hrms')
force = False
_install_app = <function install_app at 0x77bf8c4abed0>
filelock = <function filelock at 0x77bf8d4b19b0>
exit_code = 0
site = 'shirtful-erpnext.amicaldo.net'
app = 'hrms'
err = column "HR Settings" does not exist
LINE 4: doctype = "HR Settings"
^
File "apps/frappe/frappe/installer.py", line 333, in install_app
frappe.get_attr(after_install)()
name = 'hrms'
verbose = False
set_as_patched = True
force = False
sync_jobs = <function sync_jobs at 0x77bf8a96c670>
sync_for = <function sync_for at 0x77bf8a96d2d0>
sync_customizations = <function sync_customizations at 0x77bf8d50f480>
sync_fixtures = <function sync_fixtures at 0x77bf8a96e350>
installed_apps = ['frappe', 'erpnext', 'amicaldo_custom']
app = 'frappe/erpnext'
required_app = 'erpnext'
other_class_overrides = []
after_install = 'hrms.install.after_install'
app_hooks = {'accounting_dimension_doctypes': ['Expense Claim', 'Expense Claim Detail', 'Expense Taxes and Charges', 'Payroll Entry', 'Leave Encashment'], 'add_to_apps_screen': [{'name': 'hrms', 'logo': '/assets/hrms/images/frappe-hr-logo.svg', 'title': 'Frappe HR', 'route': '/desk/people', 'has_permission': 'hrms.hr.utils.check_app_permission'}], 'advance_payment_payable_doctypes': ['Leave Encashment', 'Gratuity', 'Employee Advance'], 'after_app_install': ['hrms.setup.after_app_install'], 'after_install': ['hrms.install.after_install'], 'after_migrate': ['hrms.setup.update_select_perm_after_install'], 'app_description': ['Modern HR and Payroll Software'], 'app_email': ['contact@frappe.io'], 'app_home':...rd_complete': ['hrms.subscription_utils.update_erpnext_access'], 'source_link': ['http://github.com/frappe/hrms'], 'website_generators': ['Job Opening'], 'website_route_rules': [{'from_route': '/hrms/<path:app_path>', 'to_route': 'hrms'}, {'from_route': '/hr/<path:app_path>', 'to_route': 'roster'}]}
File "apps/hrms/hrms/install.py", line 21, in after_install
raise e
BUG_REPORT_URL = 'https://github.com/frappe/hrms/issues/new'
File "apps/hrms/hrms/install.py", line 9, in after_install
setup()
BUG_REPORT_URL = 'https://github.com/frappe/hrms/issues/new'
File "apps/hrms/hrms/setup.py", line 22, in after_install
run_post_install_patches()
File "apps/hrms/hrms/setup.py", line 578, in run_post_install_patches
frappe.get_attr(f"hrms.patches.post_install.{patch_name}.execute")()
POST_INSTALL_PATCHES = ('erpnext.patches.v13_0.move_tax_slabs_from_payroll_period_to_income_tax_slab', 'erpnext.patches.v13_0.move_doctype_reports_and_notification_from_hr_to_payroll', 'erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings', 'erpnext.patches.v13_0.update_start_end_date_for_old_shift_assignment', 'erpnext.patches.v13_0.updates_for_multi_currency_payroll', 'erpnext.patches.v13_0.update_reason_for_resignation_in_employee', 'erpnext.patches.v13_0.set_company_in_leave_ledger_entry', 'erpnext.patches.v13_0.rename_stop_to_send_birthday_reminders', 'erpnext.patches.v13_0.set_training_event_attendance', 'erpnext.patches.v14_0.set_payroll_cost_centers', 'erpnext.patches.v13_0.update_empl...nce_status', 'erpnext.patches.v13_0.update_expense_claim_status_for_paid_advances', 'erpnext.patches.v14_0.delete_employee_transfer_property_doctype', 'erpnext.patches.v13_0.set_payroll_entry_status', 'create_country_fixtures', 'update_allocate_on_in_leave_type', 'update_performance_module_changes')
patch = 'erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings'
patch_name = 'move_payroll_setting_separately_from_hr_settings'
File "apps/hrms/hrms/patches/post_install/move_payroll_setting_separately_from_hr_settings.py", line 9, in execute
data = frappe.db.sql(
File "apps/frappe/frappe/database/postgres/database.py", line 234, in sql
return super().sql(modify_query(query), modify_values(values), *args, **kwargs)
self = frappe.database.postgres.database.PostgresDatabase(after_commit=frappe.utils.CallbackManager(-), after_rollback=frappe.utils.CallbackManager(-), auto_commit_on_many_writes=0, before_commit=frappe.utils.CallbackManager(-), before_rollback=frappe.utils.CallbackManager(-), cur_db_name='_0fb7d5750058b515', db_type='postgres', host='shirtful-erpnext-db', logger=<Logger database-shirtful-erpnext.amicaldo.net (WARNING)>, password='8hZNy9S8paUs07DR', port=5432, socket=None, transaction_writes=885, type_map={'Currency': ('decimal', '21,9'), 'Int': ('int', None), 'Long Int': ('bigint', None), 'Float': ('decimal', '21,9'), 'Percent': ('decimal', '21,9'), 'Check': ('smallint', None), 'Small Text': ('....frappedict._dict{'name': 'Leave Approver'}]}, 'Expense Approver': collections.defaultdict{('name'): [frappe.types.frappedict._dict{'name': 'Expense Approver'}]}}, 'DocType': collections.defaultdict{'Employee': collections.defaultdict{('name'): [frappe.types.frappedict._dict{'name': 'Employee'}]}}})
query = 'SELECT *
FROM `tabSingles`
WHERE
doctype = "HR Settings"
AND
field in (
"encrypt_salary_slips_in_emails",
"email_salary_slip_to_employee",
"daily_wages_fraction_for_half_day",
"disable_rounded_total",
"include_holidays_in_total_working_days",
"max_working_hours_against_timesheet",
"payroll_based_on",
"password_policy"
)
'
values = <exception while printing> Traceback (most recent call last):
...traceback_with_variables internal stacks...
File "apps/frappe/frappe/utils/__init__.py", line 380, in dict_printer
if key in v:
^^^^^^^^
TypeError: argument of type 'object' is not a container or iterable
args = ()
kwargs = {'as_dict': 1}
__class__ = frappe.database.postgres.database.PostgresDatabase
File "apps/frappe/frappe/database/database.py", line 272, in sql
self.execute_query(query, values)
self = frappe.database.postgres.database.PostgresDatabase(after_commit=frappe.utils.CallbackManager(-), after_rollback=frappe.utils.CallbackManager(-), auto_commit_on_many_writes=0, before_commit=frappe.utils.CallbackManager(-), before_rollback=frappe.utils.CallbackManager(-), cur_db_name='_0fb7d5750058b515', db_type='postgres', host='shirtful-erpnext-db', logger=<Logger database-shirtful-erpnext.amicaldo.net (WARNING)>, password='8hZNy9S8paUs07DR', port=5432, socket=None, transaction_writes=885, type_map={'Currency': ('decimal', '21,9'), 'Int': ('int', None), 'Long Int': ('bigint', None), 'Float': ('decimal', '21,9'), 'Percent': ('decimal', '21,9'), 'Check': ('smallint', None), 'Small Text': ('....frappedict._dict{'name': 'Leave Approver'}]}, 'Expense Approver': collections.defaultdict{('name'): [frappe.types.frappedict._dict{'name': 'Expense Approver'}]}}, 'DocType': collections.defaultdict{'Employee': collections.defaultdict{('name'): [frappe.types.frappedict._dict{'name': 'Employee'}]}}})
query = 'SELECT *
FROM "tabSingles"
WHERE
doctype = "HR Settings"
AND
field in (
"encrypt_salary_slips_in_emails",
"email_salary_slip_to_employee",
"daily_wages_fraction_for_half_day",
"disable_rounded_total",
"include_holidays_in_total_working_days",
"max_working_hours_against_timesheet",
"payroll_based_on",
"password_policy"
)'
values = None
as_dict = 1
as_list = 0
debug = False
ignore_ddl = 0
auto_commit = 0
update = None
explain = False
run = True
pluck = False
as_iterator = False
query_type = 'select'
trace_id = None
File "apps/frappe/frappe/database/database.py", line 372, in execute_query
return self._cursor.execute(query, values)
self = frappe.database.postgres.database.PostgresDatabase(after_commit=frappe.utils.CallbackManager(-), after_rollback=frappe.utils.CallbackManager(-), auto_commit_on_many_writes=0, before_commit=frappe.utils.CallbackManager(-), before_rollback=frappe.utils.CallbackManager(-), cur_db_name='_0fb7d5750058b515', db_type='postgres', host='shirtful-erpnext-db', logger=<Logger database-shirtful-erpnext.amicaldo.net (WARNING)>, password='8hZNy9S8paUs07DR', port=5432, socket=None, transaction_writes=885, type_map={'Currency': ('decimal', '21,9'), 'Int': ('int', None), 'Long Int': ('bigint', None), 'Float': ('decimal', '21,9'), 'Percent': ('decimal', '21,9'), 'Check': ('smallint', None), 'Small Text': ('....frappedict._dict{'name': 'Leave Approver'}]}, 'Expense Approver': collections.defaultdict{('name'): [frappe.types.frappedict._dict{'name': 'Expense Approver'}]}}, 'DocType': collections.defaultdict{'Employee': collections.defaultdict{('name'): [frappe.types.frappedict._dict{'name': 'Employee'}]}}})
query = 'SELECT *
FROM "tabSingles"
WHERE
doctype = "HR Settings"
AND
field in (
"encrypt_salary_slips_in_emails",
"email_salary_slip_to_employee",
"daily_wages_fraction_for_half_day",
"disable_rounded_total",
"include_holidays_in_total_working_days",
"max_working_hours_against_timesheet",
"payroll_based_on",
"password_policy"
)'
values = None
psycopg2.errors.UndefinedColumn: column "HR Settings" does not exist
LINE 4: doctype = "HR Settings"
^
Information about bug
Description:
Environment:
Context:
While installing the
hrmsapp on a site using a PostgreSQL database, the installation fails during theafter_installpatches. Specifically, the patchmove_payroll_setting_separately_from_hr_settingscontains a SQL query that uses double quotes for string literals, which PostgreSQL interprets as column identifiers.Steps to reproduce:
bench get-app hrms.bench --site [your-site] install-app hrms.Observed Result:
The installation fails with the following traceback:
Root Cause:
In
hrms/patches/post_install/move_payroll_setting_separately_from_hr_settings.py, the SQL query is:In PostgreSQL,
"HR Settings"is treated as a column name. For string literals, single quotes'HR Settings'must be used to ensure cross-database compatibility (MySQL/MariaDB and PostgreSQL).Expected Result:
The app should install successfully without SQL syntax errors.
Module
HR
Version
erpnext 16.13.3 ()
frappe 16.15.0 ()
hrms 16.5.0 version-16 (10379d4)
Installation method
docker
Relevant log output / Stack trace / Full Error Message.
Code of Conduct