NotesDocument.ComputeWithForm: Running Form Validation from Code — and Why It Won't Stop Your Save
When a user fills in a form and saves, Domino runs the form’s formulas: default values fill in, input-translation formulas tidy the data, input-validation formulas reject bad input. An agent that creates documents in the back-end skips all of that — unless you call ComputeWithForm. It’s how you get the same validation from code. But it behaves differently enough from a UI save that leaning on it naively will let invalid data straight into your database.
TL;DR
ComputeWithForm“validates a document by executing the default value, translation, and validation formulas, if any are defined in the document form.”- Signature:
flag = doc.ComputeWithForm(doDataTypes, raiseError). The first parameter is ignored in 14.5.1 — passFalse.raiseErrorchooses how failure surfaces:Trueraises a trappable error,FalsereturnsFalse. - The big gotcha: it never blocks Save. “Unlike the Notes user interface, this method allows saving documents even if ComputeWithForm returns False or raises an error.” You must gate the
Saveon the return flag yourself. - Input translation can rewrite your values. After the call, re-read any field a translation formula might have changed (
@Trim,@ProperCase, etc.). - Pin the form. It resolves the form from the stored form → the
Formitem → the database default form. On a fresh back-end document with noFormitem it silently falls back to the default form, so setdoc.Formexplicitly.
What it runs
ComputeWithForm executes three kinds of form formula against the back-end document, exactly as a save on that form would:
- Default value formulas — fill in fields the document doesn’t have.
- Input translation formulas — transform field values (trim whitespace, upper-case, format numbers).
- Input validation formulas — check the values and, via
@Failure, reject them.
What it does not do is reproduce a full UI/web save: WebQuerySave agents, QuerySave events, and other UI-side effects are outside its scope. It’s form-formula validation, not a simulation of a user clicking Save.
The signature, and the ignored parameter
flag = doc.ComputeWithForm(doDataTypes, raiseError)doDataTypes— the method ignores this parameter; the docs say “Specify either True or False.” Older tutorials describe it as a data-type check; in 14.5.1 it does nothing. PassFalse.raiseError—Trueraises a runtime error on validation failure (trap it withOn Error);FalsereturnsFalseinstead. Most code usesFalseand branches on the result.- Return —
Truemeans “no errors on the document,”Falsemeans “there are errors.”
The gotcha that lets bad data through
This is the line to tattoo on your arm, straight from the method docs: “Unlike the Notes user interface, this method allows saving documents even if ComputeWithForm returns False or raises an error.”
In the UI, failed validation stops the save. ComputeWithForm does not. It computes the pass/fail flag and hands it to you — and then does nothing to enforce it. If you call ComputeWithForm and then unconditionally Save, you’ve validated nothing; the invalid document goes in anyway. The validation only means something if you gate the save on it:
Dim session As New NotesSessionDim db As NotesDatabaseDim doc As NotesDocumentSet db = session.CurrentDatabaseSet doc = New NotesDocument(db)doc.Form = "Notification" ' pin the form — don't rely on the defaultdoc.Topic = "Large bodies of water"
If doc.ComputeWithForm(False, False) Then Call doc.Save(True, True) ' only save when validation passedElse Print "Validation failed — not saving"End IfThis is the official example, and it’s built to fail on purpose: the “Notification” form requires a Subject, but only Topic was set, so ComputeWithForm returns False and the guard skips the save. Remove the guard and the incomplete document saves regardless. To take the success path, set the required field (doc.Subject = "...") before the call.
The other two surprises
Input translation mutates your data. Translation formulas run before validation and can change field values in place — a @Trim strips your spaces, a @ProperCase re-cases a name. If downstream code depends on exactly what you wrote, re-read the field after ComputeWithForm; it may not be what you set.
Form resolution falls back silently. The method picks the form in this order: the form stored in the document, then the document’s Form item, then the database’s default form. A brand-new back-end document has no stored form and — if you didn’t set one — no Form item, so it validates against the default form, which may have entirely different fields and rules. Always set doc.Form on documents you build in code.
What about Java and SSJS?
| LotusScript | Java | SSJS / XPages |
|---|---|---|
doc.ComputeWithForm(doDataTypes, raiseError) | doc.computeWithForm(dodatatypes, raiseerror) | document.computeWithForm(...) |
The Java Document.computeWithForm(boolean, boolean) has the same two-Boolean shape and identical semantics — the first argument ignored, the second toggling exception-versus-return-false (Java throws a NotesException when it’s True). SSJS calls the same back-end method. And the “it doesn’t block save” rule holds in every language: the flag is advisory, and enforcing it is your job.