RESOURCE_COMPLETED_BEFORE_PRODUCING_VALUE had no guide, no JSDoc on
RxResourceOptions.stream, and — since the code was positive rather
than negative — could never get an auto-linked docs page even if one
existed. Flip it to -991, add the NG0991 reference page, and document
the "stream must emit a value or an error before completing"
requirement on stream's JSDoc and in the RxJS interop guide.
Also documents and tests that an unguarded template read of an
errored resource's .value() propagates to the global ErrorHandler,
and recommends guarding with .hasValue() as defense in depth.
httpResource can throw the same error, but for a different reason:
its internal request Observable isn't something app code writes
directly, so an empty completion there is almost always an
HttpInterceptor swallowing the response (catchError(() => EMPTY))
rather than a stream authored in the resource() call itself. The page
covers both APIs with guidance matched to what's actually going on
for each.
(cherry picked from commit 8975b4346d)
This started from a real production crash trace:
TypeError: Cannot read properties of null (reading 'nextSibling')
Traced through a minified bundle back to siblingAfter() in
packages/core/src/hydration/node_lookup_utils.ts. It walks forward a
fixed number of DOM siblings during hydration, based on how many the
server rendered. Its only guard, validateSiblingNodeExists(), is
gated behind ngDevMode and stripped from production builds. If the
client DOM has fewer real siblings than the server-serialized data
expects — client/server render diverged, or something outside
Angular (a browser extension, an injected script) removed a node —
the loop ran fully unguarded in production: currentNode went null
partway through, and the next iteration's currentNode.nextSibling
threw a raw, uncoded TypeError instead of a coded, debuggable one.
Reproduced first, not just theorized: added a test that server-
renders a @for loop with 3 items, removes 2 of them before hydration
runs, and confirmed it actually throws that exact TypeError against
the original code before touching anything.
Fix: add a null check at the top of the loop, matching the pattern
already used for the existing NG0500/NG0502 hydration checks in
element.ts — the dev-mode check runs first as before (a no-op in
production), and the new check is a pure safety net that only fires
once that dev-mode check has already been compiled away. In dev mode
this is provably dead code, so nothing about dev behavior changes.
Coded as NG0501 (HYDRATION_MISSING_SIBLINGS, already existed).
While investigating, found and fixed two more call sites with the
exact same shape of bug — a dev-only check that leaves production
completely unguarded:
- navigateToNode() (same file): walks an explicit "firstChild /
nextSibling" navigation path recorded for nodes that can't rely on
simple sibling-walking (e.g. content right after an <ng-content>
slot). Its only guard was also ngDevMode-only. Added the same
production safety net, both mid-loop (the raw-crash case) and
post-loop (where it could previously return null silently despite
the function's return type promising a non-null RNode). New code:
NG0509 (HYDRATION_MISSING_NODE_ON_PATH).
- getParentRElement() (render3/node_manipulation.ts): typed its
tNode parameter as always non-null, but a real production trace
showed it can be null at runtime, crashing on tNode.parent with no
useful information. Widened the type to TNode | null and added a
guard that throws a coded error instead. New code: NG0510
(PARENT_NODE_NOT_FOUND).
Unlike the other two, this one isn't gated behind ngDevMode at all
in the original code — it reproduces unconditionally. Decoded the
actual production minified stack trace against this source
(matched every frame character-for-character) to find the real
cause instead of guessing: an @if/@switch branch's content is its
own embedded template with its own TView, built lazily the first
time that branch renders. If an error interrupts that first pass —
here, a hydration mismatch on the branch's second child, after the
first child's TNode was already created — TView.firstCreatePass
still gets flipped to false in render.ts's `catch` block before the
error propagates, permanently marking that TView as corrupted.
Unlike a component's TView (rebuilt from scratch next time via
getOrCreateComponentTView()'s incompleteFirstPass check), nothing
rebuilds an embedded view's TView. The next time that exact branch
is selected again, its instructions read straight from the
corrupted tView.data instead of creating a fresh TNode, and any
node past the interruption point is still null.
The real test added for this (full_app_hydration_spec.ts) exercises
that whole chain for real: a hydration mismatch on an @if branch's
second child, then re-entering the same branch. Confirmed it throws
the exact byte-for-byte production error message ("Cannot read
properties of null (reading 'parent')") without the fix, and the
coded NG0510 with it. This replaces an earlier synthetic unit test
that just cast a variable to null to bypass the type system rather
than reproducing the actual failure.
Note: a more thorough fix would rebuild the corrupted embedded TView
itself (mirroring getOrCreateComponentTView()), which does make the
crash disappear — but doing that surfaces a second, separate bug:
the aborted first attempt's partially-created LView/DOM is never
torn down, so the retried branch's content gets appended alongside
leftover orphaned nodes instead of replacing them, corrupting
content silently instead of crashing loudly. That's a materially
bigger fix (proper LView cleanup after a mid-creation exception) and
is intentionally out of scope here; this commit keeps the narrower,
safe fix (a clear coded error) rather than trading a loud crash for
silent data corruption.
Along the way, deduplicated describeDomNode(), which existed as two
near-identical private copies (one in this file's own NG0500 check,
one in platform-browser's dom_renderer.ts insertBefore check) and
moved it into core's hydration/error_handling.ts, shared via the
private ɵdescribeDomNode export.
That function was then removed from every production code path
entirely, per review feedback: computing a human-readable node
description is debug-oriented work that shouldn't ship unconditionally
in production bundles, regardless of how cheap it is — production
should get the bare coded error only, the same as everywhere else in
this file. All three fixes above follow that: ngDevMode && 'message'
in production, no computed description. Confirmed the removal
actually shrinks output, not just assumed it: regenerated all 8
affected bundling symbol goldens, and each one shows exactly one
symbol removed — "describeDomNode" — and nothing else.
(cherry picked from commit 83f7695b2e)
Report unsupported style property binding values in development mode while preserving existing binding behavior. Unwrap trusted style values before appending unit suffixes and link NG0318 warnings to the corresponding error guide.
(cherry picked from commit e43eb96341)
`UNSAFE_IFRAME_ATTRS` in the `RuntimeErrorCode` enum is a `@deprecated`
alias of `UNSAFE_ATTRIBUTE_BINDING` (same value -910) with no usages
anywhere. Drop it along with the paired
`tslint:disable-next-line:no-duplicate-enum-values` suppression.
`RuntimeErrorCode` is re-exported as `ɵRuntimeErrorCode`, so the
enum's value set is not a stability commitment.
This API was deprecated for a longtime, and was remove by #68055 from the public API.
We do have alternatives to this old API, so we can entirely remove it to spare some bytes
Adds a utility `debounced` to create a debounced version of a signal,
represented as a `Resource`. The resource's value contained the
debounced value of the signal, while its status (`resolved`, `loading`,
or `error`) indicates if the value is settled, if there is a value
currently pending debounce, or if the source signal threw an error.
Refactors the `ɵɵcontrolCreate` and `ɵɵcontrol` instructions to delegate control logic to the forms package via new `ɵngControlCreate` and `ɵngControlUpdate` lifecycle hooks. Previously, the logic for binding form state to native elements and custom controls was hardcoded within `@angular/core`.
**Compiler Changes:**
- Introduces a new compilation phase `specializeControlProperties` (in `control_directives.ts`).
- This phase detects properties named `formField` and specializes them into `ControlCreate` and `Control` IR opcodes.
- These opcodes emit `ɵɵcontrolCreate` and `ɵɵcontrol` instructions, respectively.
**Runtime Changes:**
- `ɵɵcontrolCreate` acts as the creation phase. It locates the control directive and invokes its `ɵngControlCreate` method.
- `ɵɵcontrol` acts as the update phase, and invokes the control directive's `ɵngControlUpdate` method (if present).
- Introduces a `passThroughInput` configuration in `ControlFeature`. This specifies the input name (e.g., `formField`) that triggers the control. If the runtime detects that this input is bound to multiple targets (e.g., the `FormField` directive *and* the host component), the control is flagged as "pass-through". In this state, `ɵngControlCreate` returns a no-op update function, deferring responsibility to the other consumer (e.g., the component managing the field itself).
**Forms Changes:**
- `FormField` directive implements `ɵngControlCreate` and `ɵngControlUpdate`.
- Inside this hook, `FormField` determines the type of control it is attached to (Native, CVA, or Custom Signal Control) and delegates to the appropriate handler (`nativeControlCreate`, `cvaControlCreate`, or `customControlCreate`).
- Consolidates all form binding logic within `@angular/forms/signals`, enabling support for new `FormValueControl` and `FormCheckboxControl` interfaces.
- Reorganizes the codebase by moving `FormField` from `api/` to `directive/` and splitting the binding logic into semantic pieces:
- `control_native.ts`, `control_cva.ts`, and `control_custom.ts` contain the specific handlers for each control type.
- `native.ts` and `select.ts` provide helpers for native element discovery and select-specific synchronization.
- `bindings.ts` manages the tracking and application of property/attribute bindings.
Adds new tree-shakeable runtime error codes to improve error reporting for
NgModule resolution issues (duplicate or missing IDs) and invalid ViewContainerRef
operations involving destroyed views.
Adds new runtime sanitization error codes. Adds `ngDevMode` guards around
error message strings to ensure detailed diagnostics are included only
in development mode. This allows production builds to tree-shake verbose error descriptions, reducing bundle size.
Currently circular references in user code manifest themselves with an error like `Cannot read properties of undefined (reading 'ɵcmp')`. This is a bit cryptic so these changes add an assertion mentioning circular references.
Relates to #65917.
This commit implements a security fix to prevent XSS vulnerabilities where SVG animation elements (`<animate>`, `<set>`, etc.) could be used to modify the `href` or `xlink:href` attributes of other elements to `javascript:` URLs.
Caches information about the kind of form control that a `TNode`
represents in `TNodeFlags`. This avoids redundant computations on
subsequent template create and update passes.
Renames the `INVALID_CONTROL_HOST` error code to
`INVALID_FIELD_DIRECTIVE_HOST` for clarity and adds a test for it.
PR Close#64351
Move most of the implementation of the `Control` directive into core
framework instructions. This allows field state changes to be propagated
to their corresponding UI controls directly during execution of a
template update block, instead of relying on `effect()`s to synchronize
each change later during the update (and too late in the case of
required inputs).
* Define a private API in `@angular/core` for signal forms to implement:
* `ɵControl` for the `Control` directive.
* `ɵFieldState` for the control's associated `FieldState`.
* Emit specialized instructions when compiling a `[control]` binding:
* `ɵɵcontrolCreate` sets up the `ɵControl` directive if present,
determines whether it's bound to a native control element or a
custom control component, and adds the appropriate event listeners
to notify the `ɵFieldState` of UI changes.
* `ɵɵcontrol` propagates changes from `ɵFieldState` properties to their
corresponding UI control properties (in additional to binding the `control`
property itself).
PR Close#63773
An invalid APP_ID could be responsible to generating broken CSS selectors. (eg `:` is an example for a character that breaks a selector by being a separator for pseudo-selectors.)
We now throw an error if the provided value is not alphanumerical
PR Close#63252
Currently when loading external resources in JIT, when `fetch` fails,
the `text` is empty and the component is loading. This hides the actual
underlying fetch error. We should properly detect this and error out.
PR Close#62992
When the HMR is enabled in Angular, all `@defer` block dependencies are loaded
eagerly, instead of waiting for configured trigger conditions. From the DX perspective,
it might be seen as an issue when all dependencies are being loaded eagerly. This commit
adds a logic to produce a message into the console to provide more info for developers.
PR Close#60533
Calling `setInput` while the component already has an `inputBinding` active can lead to inconsistent state. These changes add an error that will be thrown if that's the case.
PR Close#60137
Sets up the symbols used to power the upcoming `inputBinding` functionality.
I also fixed that `setDirectiveInput` was incorrectly only allowing strings for the `value` parameter.
PR Close#60137
This commit updates the code of the incremental hydration feature to make the `DeferBlockRegistry` class tree-shakable. The class is only needed for hydration cases and it should not be included into client bundles for client-only apps.
PR Close#58424
Adds the implementation of the following new instructions:
* `declareLet` - creation-time instruction that initializes the slot for a let declaration.
* `storeLet` - update-time instruction that stores the current value of a let declaration.
* `readContextLet` - instruction that reads the stored value of a let declaration from a different view.
On top of the instructions, it also introduces a new `LetDeclaration` TNode type.
The new TNode is nececessary for DI to work correctly in pipes inside the let expression,
as well as for proper hydration support.
PR Close#56527
We don't have any docs yet for that error, so I'm removing the minus sign which indicate that there is a dedicated error doc.
Fixes#56424
PR Close#56441