
ServiceNowのUI Policyが効かない瞬間がある? onLoad Client Scriptとの競合を実機で再現する
「必須にしたはずの項目が、特定の操作だと空のまま保存できる」。テスト担当からそう指摘されたら、多くの開発者は自分が書いたonLoad Client Scriptを疑います。しかしZurich PDIで競合を再現すると、原因はUI Policyの実行順とRun scripts、参照型フィールドの罠にありました。onLoadで動くUI PolicyとClient Scriptを同じフィールドにぶつけ、最終的にどちらが勝つのかを実機で確かめます。
検証環境:Zurich PDI / OOTB / 2026-08-15 確認
UI PolicyとonLoad Client Scriptとは:どちらもフォームが表示されたときにブラウザ側で動く仕組みです。UI Policyは条件と動作を設定するだけのノーコード機能、Client Scriptはコードで自由に書ける機能です。同じフィールドの必須・読み取り専用・表示をどちらからでも操作できるため、両方を設定すると競合が起こります。onLoadは「フォームを開いた瞬間」に動くタイプで、onChangeやonSubmitとは動くタイミングが異なります。
発端は、テスト担当からの指摘だった
開発担当は、IncidentのImpactフィールドをUI Policyで必須に設定していました。条件は「Short descriptionが特定のプレフィックスで始まる」、動作は「on_loadで即座に必須にする」というシンプルな設定です。テストが始まってしばらくすると、テスト担当から2つの報告が届きました。1つは「必須にしたはずの項目が、特定の操作をすると空のまま保存できてしまう」。もう1つは、フォームを開いた瞬間だけ一瞬編集できるように見える、という報告でした。
開発担当には心当たりがありました。少し前に、別の要件でonLoad Client Scriptを同じフィールドに追加していたからです。「自分が書いたコードが、UI Policyの設定を上書きしてしまったのでは」。そう疑うのは自然な発想です。設定より後から足したコードの方が、意図的に上書きしているように見えるからです。無理もありません。
この思い込みが正しいかどうかを確かめるため、Zurich PDIで同じ状況を再現しました。UI PolicyとonLoad Client Scriptを同じImpactフィールドにぶつけ、パターンを変えながら最終的な画面の状態を1つずつ記録しています。
UI Policyのon_load処理は、onLoad Client Scriptより後に実行される
Zurich PDIでImpactフィールドを対象に3パターンのUI PolicyとClient Scriptを動かしました。Client Scriptが後からsetMandatoryで打ち消そうとしても、最終的な画面はUI Policy側の設定のまま残ります。予想と逆でした。
UI Policyだけを設定した場合、Impactは必須表示になります
onLoad Client Scriptで必須を解除するコードを足しても、画面は必須表示のまま変わりません
isLoading()によるガードを追加しても結果は同じで、しかもガード自体がエラーで動いていませんでした

上の図が実機で確認した順番です。onLoad Client Scriptは先に動きますが、その直後にUI Policyのon_load処理が走り、宣言的なMandatory設定で上書きします。Client Script側でどれだけ丁寧にガードを書いても、この順番自体は変わりませんでした。順番は固定です。UI PolicyとClient Scriptのどちらを先に作ったか、どちらを後から編集したかは、この結果に一切影響しません。
管理者は「後から書いたコードの方が強い」と考えがちである
UI Policyはノーコードの設定、Client Scriptはコードです。多くの管理者は、コードの方が自由度が高く優先されると直感的に考えます。無理もありません。設定より後から追加した機能の方が、意図的に上書きしているように見えるからです。
しかし実際にフォームが読み込まれる流れの中では、UI PolicyとClient Scriptのどちらが「後から動くか」は、設定した順番とは関係ありません。プラットフォーム側があらかじめ決めた実行順で動きます。この記事で確認したのはorderを既定値のまま使った場合の順番です。orderを変更したときに大枠の実行順まで変わるかどうかは、別途確かめる必要があります。この順番を知らずにClient Scriptを書き足すと、意図通りに動かない理由がわからないまま時間を使うことになります。
4つの場面で予想はすべて外れ、実測は別の形で効いていた
テスト担当が挙げた2つの報告は、次の4つの場面に分解できます。それぞれの場面で「管理者が直感的に予想する動き」と「実機で確認した動き」を並べると、どこにギャップがあるかがはっきりします。

上の2行は、フォームを開いた瞬間だけ一瞬編集できるという報告に対応します。原因はClient Scriptの誤動作ではなく、UI Policyが必ず最後に実行順を握っているという仕様でした。下の2行は、必須のはずが空のまま保存できるという報告に対応します。こちらの原因はUI Policy側の設定と、フィールドの型にありました。それぞれの検証内容は、この後の章で1つずつ追います。
UI PolicyとClient Scriptは、同じフォームの中で役割が異なる2つの仕組み
UI Policyは、条件に応じて表示・必須・読み取り専用を切り替える宣言的な仕組みです。フィールド単位の状態管理に特化しており、sys_ui_policy(条件)とsys_ui_policy_action(動作)の2テーブルに分かれます。Client Scriptはsys_script_clientという1つのテーブルにJavaScriptをそのまま保存する仕組みで、状態管理だけでなく計算やAPI呼び出しなど何でも書けます。
この2つの違いは、既存記事のClient ScriptとUI Policyの違い(フォーム挙動)で詳しく扱っています。今回の記事は、この2つを同じフィールドにぶつけたときに何が起こるかに焦点を絞ります。
Client Script・UI Policyそれぞれの「いつ動くか」を決める項目
sys_script_clientにはtypeという項目があり、onLoadやonChange、onSubmitなどのどこで動くかを選びます。orderという数値項目もあり、同じtypeのスクリプトが複数あるときの実行順を決めます。
UI Policy側の宣言的アクションはsys_ui_policy_actionという別テーブルに保存されます。1件のUI Policyに対して、対象フィールドの数だけこのレコードが並ぶ構造です。フォームで見えるのはMandatoryやVisible、Read onlyという3つのプルダウンですが、実データ上のフィールド名はそれぞれmandatoryとvisible、disabledです。既定値は3つとも「Leave alone(何もしない)」で、必要なものだけをTrueかFalseに変更します。今回の検証ではMandatoryだけをTrueにし、他の2つはLeave alone のままにしています。
sys_ui_policyにも同じ名前のorder項目があります。加えてon_loadという項目があり、これをオンにすると、条件変更時だけでなくフォームを開いた瞬間にもアクションが適用されます。今回の検証で使ったのは、このon_loadです。
公式ドキュメントが説明するon_loadとRun scriptsの役割
sys_documentation(フィールドの公式説明)を見ると、sys_ui_policyのon_load項目にはこう書かれていました。
Perform the actions during at form load time in addition to when the condition changes
(訳: 条件が変化したときに加えて、フォームの読み込み時にもアクションを実行します)
引用元: /sys_documentation_list.do?sysparm_query=name=sys_ui_policy^element=on_load
run_scripts項目の説明は次のとおりです。
Run scripts in response to condition checking
(訳: 条件のチェックに応じてスクリプトを実行します)
引用元: /sys_documentation_list.do?sysparm_query=name=sys_ui_policy^element=run_scripts

run_scriptsをオンにすると、UI Policyのフォームに「Script」タブが現れ、条件が真のときと偽のときにそれぞれ実行するJavaScriptを書けます。このrun_scriptsをオンにした状態では、sys_ui_policy_action側で設定した宣言的なMandatory・Visible・Read onlyのアクションが適用されませんでした。スクリプトだけが実行され、チェックボックスで設定したはずの動作は無視されます。この仕様はドキュメントの一文からは読み取れず、実機で動かして初めてわかりました。
実務での影響は小さくありません。あるUI PolicyにMandatoryのアクションが設定済みで、そこへ後から「条件が真のときに通知も出したい」という理由でrun_scriptsをオンにしてスクリプトを追記したとします。この追記だけで、既存のMandatory設定は動かなくなります。UI Policyのフォームを見る限り、Mandatoryの行には変わらず「True」と表示されたままなので、設定した本人も気づきにくい変化です。既存のUI Policyへスクリプトを足すときは、宣言的アクションが動き続けているかどうかを、フォームの見た目だけで判断しないほうが安全です。
実機で3パターンのUI Policy・Client Script組み合わせを動かす
short_descriptionの前方一致で対象を絞った3件のテストインシデントを用意しました。対象フィールドはImpact(impact)です。参照型のConfiguration itemでも試しましたが、宣言的なMandatory設定がまったく適用されない別の不具合に当たったため、選択型のImpactに切り替えています。この点は後述します。
パターンB1:UI Policyだけを設定する
UI Policyの条件は「Short descriptionがUIPで始まる」、アクションは「Impactを必須にする」、on_loadはオンです。Run scriptsはオフにし、宣言的なアクションだけで検証しました。

フォームを開いた直後、g_form.isMandatory('impact')はtrueでした。Impactのラベル横にも赤いアスタリスクが表示され、UI Policyの設定どおりに必須表示となっています。ここまでは想定どおりの結果です。
パターンB2:ガードなしのonLoad Client Scriptを重ねる
同じUI Policyに加えて、onLoad Client Scriptを1本追加しました。中身はshort_descriptionが対象のプレフィックスと一致したらg_form.setMandatory('impact', false)を呼ぶだけの単純なコードです。


このClient Scriptを追加しても、最終的なisMandatory('impact')はtrueのままでした。Impactの赤いアスタリスクも消えません。変化なしです。Client ScriptのsetMandatory(false)は確かに実行されているのに、その後でUI Policyが再び必須へ戻しています。
パターンB3:isLoadingガードを付けたonLoad Client Scriptを重ねる
「onLoad中の余計な処理を避けたい」という意図で、g_form.isLoading()が真なら処理を抜けるガードを追加したパターンも試しました。


結果はB2と同じくtrueでした。理由はB2とは異なります。ブラウザのコンソールを確認すると、次のエラーが記録されていました。
TypeError: g_form.isLoading is not a functionガードの条件式そのものが例外を投げており、setMandatory(false)まで到達していません。ガードを書いたつもりが、そもそもコードが実行されずに終わっていました。
参照型フィールドで最初につまずいた点
当初はConfiguration item(cmdb_ci、参照型)を対象にテストしていました。UI Policyだけを設定したB1相当のパターンでisMandatory('cmdb_ci')を確認すると、Client Scriptを1本も追加していないのにfalseのままでした。UI Policyの条件・アクションはg_ui_policyという内部データ上は正しく登録されており、条件も真と判定されているのに、宣言的なMandatory設定だけが反映されません。
フィールドを選択型のImpactに差し替えると、まったく同じUI Policyの設定で正しくtrueになりました。宣言的アクションの設定項目は対象フィールド、アクション種別、真偽値の3つだけです。参照型と選択型で、この設定項目に違いはありません。設定は同じです。それでも結果が変わったという事実は、フィールドの型ごとに描画の仕上がるタイミングが違う可能性を示しています。参照型は検索アイコンやワイドテキストの装飾を追加で読み込むぶん、選択型より初期化に時間がかかるはずです。UI Policyのon_load処理がその装飾の完了より早く走ると、対象の入力欄はまだ「宣言的アクションを受け取れる状態」になっていない、という筋が考えられます。この筋はあくまで推測であり、原因の切り分けまでは行っていません。
再現性は高く、同じ条件で何度試してもcmdb_ciではfalse、impactではtrueという結果が変わりませんでした。UI Policyが効かないと感じたときは、対象フィールドの型を変えて再現するかどうかも確認する価値があります。参照型のフィールドを必須にするUI Policyを組むときは、この記事の内容を踏まえて実機で一度確認しておくと安全です。
実行順は1本道だが、Run scriptsと参照型で枝分かれする
ここまでの検証結果をつなげると、フォーム表示から確定までの流れを1枚の図にまとめられます。最初の図はImpactフィールド1パターンだけの流れでしたが、この図はRun scriptsのオン・オフと、参照型フィールドで見つかった例外まで含めた全体の流れです。

フォームが表示されてからonLoadのClient Scriptが動き、UI Policyのon_load処理へ進むところまでは実機で確認した順序です。そこから先はrun_scriptsの設定で経路が分かれます。オフのまま、つまり既定の状態なら宣言的アクションがそのまま反映されて表示が確定しますが、参照型フィールドではこの経路が届かないことがあるという例外も実機で見つかりました。原因は特定できていないため、図では点線でつないでいます。オンにした場合は宣言的アクションがまるごと無視され、script_trueとscript_falseの中身だけが実行されます。このスクリプトの中で明示的にsetMandatoryを呼べば、参照型フィールドでも必須にできることを別途確認しました。
この結果が実務のトラブル調査にどう関わるか
「Client Scriptで直したのに直らない」という相談を受けたとき、原因の候補にUI Policyのon_loadを加えておくと調査が早くなります。Client Script側のコードを何度書き直しても、UI Policyが同じフィールドに宣言的なアクションを持っている限り、最終的な表示はUI Policy側に戻ります。
isLoading()のようなガードを足しても、それだけでは解決しません。今回確認した限り、g_form.isLoading()はonLoad Client Scriptの中で呼び出すと例外になります。ガードのつもりで書いたコードがそもそも動いていない可能性を、まず疑ってください。
run_scriptsを有効にしたUI Policyを見つけたときは、宣言的なアクション欄の設定を鵜呑みにしないことです。Scriptタブの中身が実際に何をしているかを読まないと、フォーム上の挙動を正しく説明できません。
ブラウザのコンソールでエラーを見つける手順
Client Scriptのエラーは、フォーム上のどこにも表示されません。原因を切り分けるには、ブラウザの開発者ツールを自分で開く必要があります。
Chromeであれば、フォームを開いた状態でF12キーを押し、Consoleタブを選びます。フォームを再読み込みすると、onLoad系のスクリプトが実行されるたびにログが流れます。今回のようなエラーがあれば、赤字で「TypeError」や「ReferenceError」という表示が混ざるはずです。ログの量が多いときは、検索欄に対象のClient Script名の一部を入力すると、該当行を絞り込めます。
エラーが1件も無いのにUI Policyが期待どおり動かない場合は、run_scriptsの設定を疑う番です。エラーの有無とrun_scriptsの設定は、原因の系統がまったく異なります。この2つを順番に切り分けると、闇雲にコードを直す時間を減らせます。
疑うときの確認順です。
対象フィールドにsys_ui_policy_actionの設定がないかを確認する。あればon_loadがオンかどうかも見る
そのUI Policyでrun_scriptsがオンになっていないかを確認する。オンならScriptタブの中身を読む
Client Script側にisLoading()のようなガードがあれば、ブラウザのコンソールでエラーが出ていないかを確認する
3パターンの結果は、後述の表にまとめています。Client Script側の書き方を変えても、最終結果はどれも同じでした。
この競合はOOTBの仕様として受け止め、Client Scriptの役割を規約で絞るべきである
ここまでの実測を踏まえると、この実行順そのものを設定で変えようとするのは筋が悪いという判断になります。推奨は1つに絞ります。onLoadでのUI Policy優先はプラットフォームがあらかじめ決めた仕様です。変えるべきは設定ではなく、フィールド制御をどちらの仕組みに書くかという開発の規約です。
判定は場面ごとに次の4つです。

一番上の判定が起点です。フィールド制御を宣言的UI Policyへ一本化すれば、残り3つの判定は自然に導かれます。Client Script側で同じ属性を操作しない以上、onLoadで書ける処理はUI Policyでできないことに絞られるという理屈です。Run scriptsを足すときは既存の宣言的アクションを壊さない書き方が要り、参照型フィールドで宣言的アクションが効かないときの回避策も、同じくスクリプト側で明示的に処理を書く形に落ち着きます。
この判断は、そのまま開発の規約として使える形に落とせます。
フィールドの必須・表示・読み取り専用は、原則として宣言的UI Policyだけで制御する。Client Scriptから同じ属性を操作しない
onLoad Client Scriptは、UI Policyの宣言的アクションでは実現できない処理(初期値の計算、他システムからの値取得、フォーカス制御など)に限定して使う
既存のUI Policyへスクリプトを追記するときは、run_scriptsが宣言的アクションを丸ごと無効化する前提で扱う。追記の際は、既存の宣言的アクションと同じ内容をscript_trueとscript_falseの中に明示的に書き直す
参照型フィールドを宣言的アクションで必須にできないときは、run_scriptsを有効化してsetMandatoryを明示的に呼ぶ。適用結果は必ずisMandatoryで実機確認してから本番へ反映する
4つ目の判断は、この記事のために新しくUI Policyを1件作り、run_scripts経由のsetMandatory呼び出しが参照型フィールドでも機能することを実機で確かめた上でのものです。宣言的Mandatoryの代わりにsys_dictionary側のmandatory属性を使う方法も理論上は考えられますが、影響範囲がテーブル全体に及ぶため今回は検証していません。詳しい経緯と後始末は末尾の検証範囲に記載しています。
実機で気づいたこと
見落としやすいのは、g_form.isLoading()のエラーの扱いです。ブラウザのコンソールには出ているのに、画面上にはまったく表示されません。ServiceNowのレンダリングエンジンは、onLoad系のスクリプトでエラーが起きても止まりません。「Script ends. Continuing happily」という一文をコンソールに残すだけで、次の処理へ進みます。管理者がこのメッセージを見に行かない限り、ガードが機能していないことに気づく手段がありません。
Client Scriptのフォームを開くと、青い注記がありました。文言は「New client-scripts are run in strict mode, with direct DOM access disabled」です。新規作成したClient Scriptは、既定でIsolate scriptがオンです。windowオブジェクトへの直接アクセスなどが制限された状態で動いています。isLoadingのような未定義の識別子を参照すると、この制限とは別に、そもそも関数が存在しないというエラーになります。ガードを書くつもりで存在しないAPIを呼んでしまう事故は、起こり得る失敗です。

3件とも最終的な状態は同じでしたが、途中の経路はB2とB3で違いました。この違いに気づけたのは、isMandatoryの値だけでなくブラウザのコンソールも一緒に見ていたからです。画面の見た目だけを比べていたら、B3のガードが例外で壊れていることには気づけませんでした。
run_scriptsをオンにしたときに宣言的アクションが無視される挙動も、事前には知りませんでした。UI Policyのフォーム自体には、Run scriptsと宣言的アクションが同時に効かなくなるという注意書きはありません。チェックボックス1つで動作モードが切り替わる設計だと考えると、既存のUI Policyを流用してScriptタブだけ追加するような変更は、慎重に検証したほうがいいとわかりました。
参照型フィールドでの回避策を探しているときにも、意外な発見がありました。宣言的なMandatoryは効かなかったのに、run_scriptsのスクリプトから同じsetMandatoryを明示的に呼ぶと、参照型でも即座に反映されました。宣言的アクションの処理経路だけに何らかの制約があり、Client Script側のAPI自体は参照型でも普通に動くことがわかります。
用語(実行順)
onLoad Client Script(sys_script_client, type=onLoad) … フォームが開いた直後に自動で実行されるコード
UI Policyのon_load処理(sys_ui_policy, on_load=true) … onLoad Client Scriptの直後に実行され、宣言的アクションを適用して上書きする
sys_ui_policy_action … UI Policy 1件につき複数持てる、フィールド単位の宣言的な動作設定
run_scripts … オンにすると宣言的アクションの代わりにscript_true/script_falseだけが実行される切り替え
Isolate script(sys_script_client, isolate_script) … 新規Client Scriptで既定オンになる、strict modeでの実行設定。DOMやwindowへの直接アクセスを制限する
script_true / script_false(sys_ui_policy, run_scripts=trueのときに実行されるスクリプト) … 宣言的アクションが効かない場合でも、この中でg_formのメソッドを明示的に呼べば反映される
自分の環境で確認するときのURL
/sys_ui_policy_list.do?sysparm_query=table=incident^active=true^on_load=true … incidentでon_loadが有効なUI Policy一覧
/sys_script_client_list.do?sysparm_query=table=incident^type=onLoad^active=true … incidentのonLoad Client Script一覧
/sys_documentation_list.do?sysparm_query=name=sys_ui_policy^hintISNOTEMPTY … sys_ui_policyの各項目の公式説明
/sys_ui_policy_list.do?sysparm_query=table=incident^run_scripts=true^active=true … incidentでRun scriptsが有効なUI Policy一覧。宣言的アクションが効いていないおそれがある一覧
引用した公式説明を自分で開く
この記事で引用した説明文は、ServiceNowが製品に同梱しているフィールドのドキュメントです。次のURLを自分のインスタンスで開くと、同じ記述がフォームの中に見つかります。
on_load / run_scriptsの公式説明(引用元):/sys_documentation_list.do?sysparm_query=name=sys_ui_policy^element=on_load^ORname=sys_ui_policy^element=run_scripts
参考リンク
Create a UI Policy(Zurich) — UI Policyの作成手順を説明する公式ページ
Client scripts(Zurich API Reference) — Client Scriptの種類とAPIの公式リファレンス
Form administration(Zurich) — フォーム管理機能全体の公式ランディングページ
GlideForm (g_form) - Client — g_formで使えるメソッド一覧の公式リファレンス
検証範囲とおことわり
挙動はZurich PDI(OOTB)で2026-08-15に確認したものです。テストはshort_descriptionの前方一致で既存データと隔離した3件のインシデントを対象にしており、本番相当のデータやカスタマイズ済みの環境では読み込み順が異なる可能性があります。
検証はクラシックUIのIncidentフォーム、onLoadタイプのClient Scriptに限定しました。onChangeやonSubmitでの競合、Agent WorkspaceのようなNext Experience UIでの挙動、カタログ画面での競合は今回の検証範囲の外です。参照型フィールドで宣言的アクションが適用されなかった現象も、原因の切り分けまでは行っていません。Isolate scriptをオフにした場合にisLoading系のエラーが変わるかどうかも、今回は確認していません。作成したUI Policy 2件とClient Script 2件は、検証後にActiveをfalseへ戻しました。テスト用に作成したインシデント(INC0010465〜INC0010467、INC0010474)はデータとして残しています。参照型フィールドの回避策はrun_scripts経由の明示呼び出しだけを検証しており、sys_dictionary側のmandatory属性を使う方法は影響範囲がテーブル全体に及ぶため試していません。
関連記事
ServiceNowで項目が画面に出ないのはなぜ? ビュー・UI Policy・ACLを順番に切り分ける — UI Policyが絡む別のトラブルパターンを扱う実務編
ServiceNowで処理を書くならどこ? Business Rule・Client Script・ACLの使い分けを実機の件数から考える — Client Scriptをどこまで使うべきかの判断材料
ServiceNowの入力チェックはClient ScriptとBusiness Ruleのどちらに書く? 実機の件数と判断基準 — Client Scriptの使いどころをさらに広い視点で見る