bcquality/microsoft/knowledge/performance/use-tryfunction-for-error-catching-not-rollback.md
Kilian Seizinger da5a28819e knowledge(error-handling): a bare [TryFunction] call propagates its error
The review agent repeatedly flagged bare calls to [TryFunction] procedures
(e.g. the System Application "Xml Validation" Try* APIs) as defects,
including claims that the failure is "silently swallowed". A bare call is
an ordinary call: the error propagates as usual.

- Add negative knowledge bare-tryfunction-call-propagates-errors.md.
- Narrow ignored-tryfunction-return-disables-try-semantics to code that
  visibly expects the failure to be caught; the bad sample now shows that
  in code, and the good sample includes an intentional bare call as the
  clean control.
- Qualify "TryFunction catches all errors" in the events article and the
  "must be consumed" wording in the performance article.
- Error-handling leaf worklists both articles for bare [TryFunction] calls
  and requires the same evidence before flagging.
- Add the three paired articles to the evaluation overrides.
2026-10-02 14:30:51 +02:00

32 lines
3 KiB
Markdown

---
bc-version: [all]
domain: performance
keywords: [try-function, try-method, error-handling, rollback, atomic, exception, get-last-error, session-buffer]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Use [TryFunction] for error catching, Codeunit.Run for atomic rollback
## Description
`[TryFunction]` lets a caller catch an error, but database changes made before that error are not rolled back. The attribute catches; it does not unwind transaction state. This is the critical distinction from `Codeunit.Run`, which can provide an atomic rollback boundary (see `codeunit-run-as-atomic-sub-operation.md`). On Business Central on-premises, writes inside a try method are blocked by default unless `DisableWriteInsideTryFunctions` is set to `false`; SaaS does not provide that server setting.
## Best Practice
Reach for `[TryFunction]` when you want to catch a failure without unwinding the transaction — for example, third-party interop or parsing whose error you intend to translate. When writes must either fully apply or fully revert, use `Codeunit.Run` instead. The two primitives solve different problems: one catches errors, the other bounds a rollback scope.
Use `[TryFunction]` sparingly. Each caught error writes to the session-wide `GetLastErrorText` and `GetLastErrorCallStack` buffers, and every subsequent catch overwrites the earlier state — a helper that reads `GetLastErrorText` later may see a different error than the one it intended to inspect. Prefer explicit checks (non-throwing predicates, guard conditions, upfront validation) for operations with predictable failure modes; reserve `[TryFunction]` for genuinely unpredictable failures such as network calls, third-party interop, or evaluation of user-supplied expressions. When you do catch, read `GetLastErrorText` immediately after the failed call, and call `ClearLastError` before the call if an earlier catch in the same scope could have left state behind — per the platform reference, "If you call the GetLastErrorText method immediately after you call the ClearLastError method, then an empty string is returned."
See sample: [`use-tryfunction-for-error-catching-not-rollback.good.al`](use-tryfunction-for-error-catching-not-rollback.good.al).
## Anti Pattern
Wrapping database writes in `[TryFunction]` and expecting successful writes before the error to roll back. They remain, the caller receives `false`, and partially applied state can escape. Defensive sprinkling is also unsafe: every catch overwrites the session error buffer and can hide the failure a later helper intended to inspect.
See sample: [`use-tryfunction-for-error-catching-not-rollback.bad.al`](use-tryfunction-for-error-catching-not-rollback.bad.al).
## See also
`microsoft/knowledge/error-handling/ignored-tryfunction-return-disables-try-semantics.md` owns the separate call-site rule that only a call that consumes the Boolean result catches errors; `microsoft/knowledge/error-handling/bare-tryfunction-call-propagates-errors.md` records that a bare call propagates them as intended.