Dolibarr/dolibarr · error

Error in trigger

Error message

Error in trigger: ${invoice->errorsToString()}

What it means

document.php can run in 'attachment' style flows where calling a trigger on an invoice-like object fails; when $invoice->call_trigger() returns < 0 the code sends HTTP 500 and prints 'Error in trigger: <errorsToString()>'. Trigger handlers (modules implementing BILL_... triggers) signaled a failure via $object->errors.

Solutions

  1. Read $invoice->errorsToString() output to find the failing trigger/module
  2. Check the module's trigger code in htdocs/<module>/class/triggers_*.class.php and its logs
  3. Fix or disable the faulty trigger module
  4. Ensure trigger code uses $object->errors = array(...) and returns < 0 only on genuine failure
  5. Confirm the object is fully loaded (fetch) before call_trigger in custom code

Example fix

// before (trigger)
$result = $object->update($user); // errors not captured
// after
$res = $object->update($user);
if ($res < 0) { $this->errors = $object->errors; return -1; }
Defensive patterns

Strategy: try-catch

Try / catch

$result = $object->call_trigger($action, $user);
if ($result < 0) {
    http_response_code(500);
    error_log('Trigger failed: '.implode(', ', $object->errors));
}

Prevention

When it happens

Trigger: A trigger action (e.g. BILLSENTBYMAIL, BILL_PAYED) fired during a document.php request whose handler returns negative / fills $object->errors; typically when sending a document by email or registering a payment-like action through the download endpoint.

Common situations: A third-party module's trigger has a bug or missing dependency; database write inside trigger fails; trigger code not updated after a core version upgrade; trigger expects a fully loaded object that document.php's minimal stdClass context lacks.

Related errors


AI-assisted analysis of Dolibarr/dolibarr@598aa4bdad (2026-09-14). Data as JSON: /api/errors/3a2d6964b2d51d67. Report an issue: GitHub.

Appendix: source

Thrown at htdocs/document.php:437

				$moreparams = '';
				$hidedetails = isset($hidedetails) ? $hidedetails : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0); // @phpstan-ignore-line as variable $hidedetails is forced
				$hidedesc = isset($hidedesc) ? $hidedesc : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0); // @phpstan-ignore-line as variable $hidedesc is forced
				$hideref = isset($hideref) ? $hideref : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0); // @phpstan-ignore-line as variable $hideref is forced
				$moreparams = isset($moreparams) ? $moreparams : null; // @phpstan-ignore-line as variable $moreparams is forced

				$result = $invoice->generateDocument($invoice->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
				if ($result < 0) {
					dol_syslog("Failed to regenerate PDF", LOG_WARNING);
				}
			}

			// Call trigger
			$result = $invoice->call_trigger($action, $user);
			if ($result < 0) {
				top_httphead();

				http_response_code(500);
				print 'Error in trigger: '.$invoice->errorsToString();
				exit;
			}
		}
	}
}



// Permissions are ok and file found, so we return it
top_httphead($type);

header('Content-Description: File Transfer');
if ($encoding) {
	header('Content-Encoding: '.$encoding);
}
// Add MIME Content-Disposition from RFC 2183 (inline=automatically displayed, attachment=need user action to open)

if ($attachment > 0) {

View on GitHub (pinned to 598aa4bdad)