{"record":{"id":"837c4ff6164d45b3","repo":"Dolibarr/dolibarr","slug":"error-in-some-triggers-user-login-or-in-some-hooks","errorCode":null,"errorMessage":"Error in some triggers USER_LOGIN or in some hooks afterLogin","messagePattern":"Error in some triggers USER_LOGIN or in some hooks afterLogin","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"htdocs/main.inc.php","lineNumber":1165,"sourceCode":"\t\t$result = $user->call_trigger('USER_LOGIN', $user);\n\t\tif ($result < 0) {\n\t\t\t$error++;\n\t\t}\n\t\t// End call triggers\n\n\t\t// Hooks on successful login\n\t\t$action = '';\n\t\t$hookmanager->initHooks(array('login'));\n\t\t$parameters = array('dol_authmode' => $dol_authmode, 'dol_loginfo' => $loginfo);\n\t\t$reshook = $hookmanager->executeHooks('afterLogin', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks\n\t\tif ($reshook < 0) {\n\t\t\t$error++;\n\t\t}\n\n\t\tif ($error) {\n\t\t\t$db->rollback();\n\t\t\tsession_destroy();\n\t\t\tdol_print_error($db, 'Error in some triggers USER_LOGIN or in some hooks afterLogin');\n\t\t\texit;\n\t\t} else {\n\t\t\t$db->commit();\n\t\t}\n\n\t\t// Change landing page if defined.\n\t\t$landingpage = getDolUserString('MAIN_LANDING_PAGE', getDolGlobalString('MAIN_LANDING_PAGE'));\n\t\tif (!empty($landingpage)) {    // Example: /index.php\n\t\t\t$newpath = dol_buildpath($landingpage, 1);\n\t\t\tif ($_SERVER[\"PHP_SELF\"] != $newpath) {   // not already on landing page (avoid infinite loop)\n\t\t\t\theader('Location: '.$newpath);\n\t\t\t\texit;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check if user must change password at next login\n\tif (!empty($user->force_pass_change) && $dol_authmode == 'dolibarr') {","sourceCodeStart":1147,"sourceCodeEnd":1183,"githubUrl":"https://github.com/Dolibarr/dolibarr/blob/598aa4bdada683d17ca04b1842548821ff0eb6c6/htdocs/main.inc.php#L1147-L1183","documentation":"During login, Dolibarr fires the USER_LOGIN trigger and the afterLogin hooks inside a transaction. If any trigger or hook returns an error ($error > 0), main.inc.php rolls back the transaction, destroys the session, prints this hardcoded diagnostic via dol_print_error() and exits. It means a third-party module's trigger/hook is failing, not core Dolibarr.","triggerScenarios":"Calling login (web form or API /api/index.php/login) when a module implementing USER_LOGIN (e.g. an LDAP, SSO, or custom business module) raises/returns an error, or an afterLogin hook returns < 0.","commonSituations":"After installing/upgrading a third-party module; a custom trigger with a bug or unmet dependency (e.g. LDAP server unreachable); module disabled mid-way leaving broken trigger registration; PHP fatal in hook code.","solutions":["Check the PHP/server error log and Dolibarr logs (dol_syslog output) for the underlying exception from the trigger/hook.","Disable recently added/updated modules (run.php setconst or remove the module directory in htdocs/custom) and retry login.","Inspect llx_document_model / the triggers directory of enabled modules: fix the module's addtrigger/USER_LOGIN code so it returns 0 on success and handles its own DB errors.","If LDAP/SSO integration is the trigger, verify the external server is reachable and credentials valid.","Test with only core modules enabled (empty htdocs/custom) to isolate the culprit module."],"exampleFix":"// before (custom trigger)\nfunction runTrigger($action, $object, User $user, Translate $langs, Conf $conf) {\n    doRiskyLdapSync($user); // may throw / return error\n}\n// after\nfunction runTrigger($action, $object, User $user, Translate $langs, Conf $conf) {\n    try { doRiskyLdapSync($user); } catch (Exception $e) {\n        dol_syslog('USER_LOGIN trigger failed: '.$e->getMessage(), LOG_ERR);\n        return 0; // don't block login\n    }\n    return 0;\n}","handlingStrategy":"try-catch","validationCode":"// before deploying a module, smoke-test its USER_LOGIN trigger\nforeach (glob(DOL_DOCUMENT_ROOT.'/custom/*/core/triggers/*.class.php') as $f) {\n    require_once $f; // fatal here means login will break\n}","typeGuard":"function triggerReturnsInt(callable $trigger): bool {\n    // every Dolibarr trigger must return <0, 0 or >0, never null/throw\n    try { $r = $trigger(); return is_int($r); } catch (Throwable $e) { return false; }\n}","tryCatchPattern":"try {\n    $result = $client->post('/api/index.php/login', $credentials);\n} catch (ServerException $e) {\n    // check logs for 'Error in some triggers USER_LOGIN'\n    disableRecentlyAddedModules();\n}","preventionTips":["Test module install/upgrade on staging before production.","Keep triggers cheap and failure-tolerant: never let external-service outages (LDAP, SSO) block login.","Return 0 (not null, no exceptions) from runTrigger on non-fatal issues.","Monitor dol_syslog warnings during login in CI.","Keep htdocs/custom under version control so a bad module can be reverted instantly."],"tags":["login","triggers","hooks","modules"],"backgroundTag":"api-error-response","analyzedSha":"598aa4bdada683d17ca04b1842548821ff0eb6c6","analyzedAt":"2026-09-14T11:12:15.309Z","contentChangedAt":"2026-09-14T11:12:15.309Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}