{"record":{"id":"150427317a8bb455","repo":"Dolibarr/dolibarr","slug":"error-not-logged","errorCode":"ERROR_NOT_LOGGED","errorMessage":"ERROR_NOT_LOGGED","messagePattern":"ERROR_NOT_LOGGED","errorType":"error_code","errorClass":null,"httpStatus":401,"severity":"info","filePath":"htdocs/main.inc.php","lineNumber":865,"sourceCode":"\t\t\t\t$reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks\n\t\t\t\tif ($reshook < 0) {\n\t\t\t\t\t$error++;\n\t\t\t\t}\n\n\t\t\t\t// Note: exit is done in next chapter\n\t\t\t}\n\t\t}\n\n\t\t// End test login / passwords\n\t\tif (!$login || (in_array('ldap', $authmode) && !in_array('openid_connect', $authmode) && empty($passwordtotest))) {     // With LDAP we refused empty password because some LDAP are \"opened\" for anonymous access so connection is a success.\n\t\t\t// No data to test login, so we show the login page.\n\t\t\tdol_syslog(\"--- Access to \".(empty($_SERVER[\"REQUEST_METHOD\"]) ? '' : $_SERVER[\"REQUEST_METHOD\"].' ').$_SERVER[\"PHP_SELF\"].\" - action=\".GETPOST('action', 'aZ09').\" - actionlogin=\".GETPOST('actionlogin', 'aZ09').\" - showing the login form and exit\", LOG_NOTICE);\n\t\t\tif (defined('NOREDIRECTBYMAINTOLOGIN')) {\n\t\t\t\t// When used with NOREDIRECTBYMAINTOLOGIN set, the http header must already be set when including the main.\n\t\t\t\t// See example with selectsearchbox.php. This case is reserved for the selectesearchbox.php so we can\n\t\t\t\t// report a message to ask to login when search ajax component is used after a timeout.\n\t\t\t\t//top_httphead();\n\t\t\t\treturn 'ERROR_NOT_LOGGED';\n\t\t\t} else {\n\t\t\t\tif (!empty($_SERVER[\"HTTP_USER_AGENT\"]) && $_SERVER[\"HTTP_USER_AGENT\"] == 'securitytest') {\n\t\t\t\t\thttp_response_code(401); // It makes easier to understand if session was broken during security tests\n\t\t\t\t}\n\n\t\t\t\t// Show login form\n\t\t\t\tdol_loginfunction($langs, $conf, (!empty($mysoc) ? $mysoc : ''));\t// This include http headers\n\t\t\t}\n\t\t\texit;\n\t\t}\n\n\t\t$resultFetchUser = $user->fetch(0, $login, '', 1, ($entitytotest > 0 ? $entitytotest : -1)); // value for $login was retrieved previously when checking password.\n\n\t\tif ($resultFetchUser <= 0 || $user->isNotIntoValidityDateRange()) {\n\t\t\tdol_syslog('User not found or not valid, connection refused');\n\t\t\tsession_destroy();\n\t\t\tsession_set_cookie_params(0, '/', null, !empty($dolibarr_main_force_https), true); // Add tag secure and httponly on session cookie\n\t\t\tsession_name($sessionname);","sourceCodeStart":847,"sourceCodeEnd":883,"githubUrl":"https://github.com/Dolibarr/dolibarr/blob/598aa4bdada683d17ca04b1842548821ff0eb6c6/htdocs/main.inc.php#L847-L883","documentation":"When a request reaches a protected page without a logged-in user, Dolibarr normally redirects to the login page. However, if NOREDIRECTBYMAINTOLOGIN is defined (e.g. AJAX components like selectsearchbox.php), main.inc.php instead returns the literal string 'ERROR_NOT_LOGGED' so the including script can handle the unauthenticated state itself; a 401 is optionally sent when the user agent is 'securitytest'.","triggerScenarios":"Session expired or no user in session while including main.inc.php in a script that defines NOREDIRECTBYMAINTOLOGIN; AJAX endpoints hit after a session timeout.","commonSituations":"AJAX search components polling after the session timed out; headless/API-style scripts expecting a return code rather than a redirect; automated tests sending User-Agent 'securitytest' and receiving 401.","solutions":["Log in again or re-establish the session before calling the AJAX endpoint.","Make the AJAX client handle the ERROR_NOT_LOGGED return by redirecting to the login page.","In custom scripts, check the return value of the main.inc.php inclusion and handle it.","For tests, expect the 401 status rather than parsing HTML.","If a full-page redirect is desired, remove the NOREDIRECTBYMAINTOLOGIN define."],"exampleFix":"// before\n@require './main.inc.php';\n// after\n$res = require './main.inc.php';\nif ($res === 'ERROR_NOT_LOGGED') { top_httphead('application/json'); echo '{\"error\":\"not_logged\"}'; exit; }","handlingStrategy":"fallback","validationCode":"if (empty($user->id)) { /* not logged in yet, handle before protected calls */ }","typeGuard":null,"tryCatchPattern":"$res = require __DIR__.'/main.inc.php';\nif ($res === 'ERROR_NOT_LOGGED') { http_response_code(401); exit; }","preventionTips":["In AJAX clients, treat 401/not-logged responses by reloading the login page","Keep sessions alive with keep-alive pings for long-running pages","Check main.inc.php's return value when using NOREDIRECTBYMAINTOLOGIN"],"tags":["dolibarr","session","authentication"],"backgroundTag":"authentication-required","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"}