Skip to content

[#186] Fix "Internal Error" in mapping Sample Source / Single Record Reconciliation when first property has no source#188

Open
vharseko wants to merge 4 commits into
OpenIdentityPlatform:masterfrom
vharseko:issues/187
Open

[#186] Fix "Internal Error" in mapping Sample Source / Single Record Reconciliation when first property has no source#188
vharseko wants to merge 4 commits into
OpenIdentityPlatform:masterfrom
vharseko:issues/187

Conversation

@vharseko
Copy link
Copy Markdown
Member

@vharseko vharseko commented Jun 4, 2026

Fixes #186

Summary

Using Sample Source (Properties tab) or Single Record Reconciliation
(Behaviors tab) returned an "Internal Error" with nothing meaningful in the logs
whenever the first property of a mapping had no source (e.g. a
transform-only / target-only property).

Root cause

The admin UI built the autocomplete property list with
_.pluck(mapping.properties, "source") and took the first N elements without
checking whether they were defined. When the first property had no source, a
leading undefined ended up in the list and was passed down to
SearchDelegate.searchResults, which injected props[0] directly into the URL:

/managed/user?_sortKeys=&_pageSize=10&_queryFilter=...

The empty _sortKeys= is rejected by the CREST/IDM backend, producing an
HTTP 500 that surfaced only as a generic "Internal Error" (the failure was
logged via console.error only).

Changes

Defensive fix (lowest level)

  • SearchDelegate.js — extracted URL construction into a testable
    buildSearchUrl(...). _sortKeys is now derived from the first non-empty
    property; if no usable property exists, the _sortKeys parameter is omitted
    entirely. This guarantees an empty _sortKeys= can never be emitted again,
    even if a "leaky" property array is passed in the future.
    In addition, _sortKeys is omitted for system/... resources, because
    many connectors (e.g. the CSV connector used by the getting-started sample)
    do not support server-side sorting and would otherwise fail the whole sample
    query with an HTTP 500. Sample searches are capped at a few results, so the
    sort order is not required.

Source fixes (UI views)

  • SingleRecordReconciliationView.jssetupSearch now filters out empty
    source values before slicing the representative props.
  • AttributesGridView.js — same filtering for the dynamic Sample Source.
  • DataAssociationManagementView.js — same filtering for both source and
    target representative props.
  • MappingUtils.jssetupSampleSearch compacts the property list and
    guards valueField / searchField against undefined.

Important — _.first vs _.take (lodash 3) regression. The admin UI maps
underscorelodash-3.10.1. In lodash 3, _.first(array, n) ignores n
and returns only the first element. An earlier iteration of the view fixes
used _.chain(...).pluck("source").filter(...).first(numRepresentativeProps),
which therefore returned the single string "email" instead of an array. That
string was then spread into characters (["e","m","a","i","l"]), producing a
malformed query (e sw "Sanchez" or (m sw "Sanchez" or ...)) that the system
endpoint rejected with HTTP 400, leaving the dropdown empty. The final fix
uses native Array.prototype.filter().slice(0, n) in all three views, which is
library-agnostic and verified against a live getting-started instance.

Tests

  • SearchDelegateTest.js — added QUnit tests for buildSearchUrl:
  • MappingUtilsTest.js — added QUnit tests for setupSampleSearch:
    • the selectize load callback receives a flat array of records;
    • valueField/searchField skip properties without a source.

Affected files

File Change
openidm-ui/openidm-ui-common/.../delegates/SearchDelegate.js buildSearchUrl helper; never emit empty _sortKeys=; skip _sortKeys for system/... resources
openidm-ui/openidm-ui-admin/.../mapping/behaviors/SingleRecordReconciliationView.js Filter empty source in setupSearch
openidm-ui/openidm-ui-admin/.../mapping/properties/AttributesGridView.js Filter empty source for Sample Source
openidm-ui/openidm-ui-admin/.../mapping/association/DataAssociationManagementView.js Filter empty source/target
openidm-ui/openidm-ui-admin/.../mapping/util/MappingUtils.js Compact props; guard valueField/searchField; pass flat array to selectize load
openidm-ui/openidm-ui-common/.../test/.../SearchDelegateTest.js New tests for buildSearchUrl
openidm-ui/openidm-ui-admin/.../test/.../MappingUtilsTest.js New tests for setupSampleSearch

How to test

  1. Create a mapping whose first property has no source (transform/target-only).
  2. Open the Properties tab and use Sample Source — autocomplete works,
    no "Internal Error".
  3. Open the Behaviors tab and use Single Record Reconciliation — sample
    search works as expected.
  4. Run the UI QUnit suite — Search Delegate Tests pass, including the new
    buildSearchUrl cases.
  5. Run the getting-started Playwright suite
    (OPENIDM_SAMPLE=samples/getting-started) — the Sample Source 'Sanchez'
    test passes: typing Sanchez shows the Jane Sanchez dropdown option and
    selecting it populates the preview (the system/hr/account CSV connector no
    longer fails on _sortKeys).

…penIdentityPlatform#186)

Build the sample-search URL via a new buildSearchUrl helper that derives
_sortKeys from the first non-empty property and omits the parameter entirely
when no usable property exists, so an empty "_sortKeys=" can never be sent
to the CREST/IDM backend.

Filter out properties without a source/target in mapping sample search (OpenIdentityPlatform#186)

SingleRecordReconciliationView, AttributesGridView and
DataAssociationManagementView now keep only properties that actually define a
source (and target), preventing a leading undefined value from breaking the
sample search query. MappingUtils.setupSampleSearch compacts the property list
and guards selectize valueField/searchField against undefined.
Add SearchDelegate.buildSearchUrl tests for empty _sortKeys handling (OpenIdentityPlatform#186)

Cover the normal case, the leading-undefined fallback to the first non-empty
property, and full omission of _sortKeys when no property is usable.
vharseko added 3 commits June 4, 2026 18:09
…mple search (OpenIdentityPlatform#186)

Build the sample-search URL via a new buildSearchUrl helper that derives
_sortKeys from the first non-empty property, omits the parameter entirely when
no usable property exists, and skips _sortKeys for system/... resources whose
connectors (e.g. the CSV connector) may not support server-side sorting. This
prevents both the empty "_sortKeys=" and the unsupported-sort HTTP 500 errors.
…yPlatform#186)

MappingUtils.setupSampleSearch passed the search results to the selectize
`load` callback wrapped in an extra array (callback([response])). Since
SearchDelegate.searchResults already resolves to a flat array of records,
this produced a nested [[record, ...]] structure: selectize treated the inner
array as a single option, _.pick() returned an empty object, and the dropdown
showed one empty, unselectable entry instead of the matching record. As a
result the getting-started "Sample Source 'Sanchez'" flow never displayed the
"Jane Sanchez" option.

Pass the results through as a flat array (callback(response)) and guard the
success branch with response.length so an empty result set falls back to the
no-results callback.

Add MappingUtilsTest coverage for setupSampleSearch:
- the selectize `load` callback receives a flat array of records;
- valueField/searchField skip properties without a `source`.
…latform#186)

The admin UI maps underscore to lodash 3.10.1, where _.first(array, n)
ignores n and returns only the first element. Building the representative
property list via _.chain().pluck("source").filter().first(n).value()
therefore yielded the single string "email" instead of an array; it was
then spread into characters, producing a malformed _queryFilter
(e sw "..." or (m sw "..." ...)) that the system endpoint rejected with
HTTP 400, leaving the sample-source dropdown empty.

Build the representative props with native Array filter().slice(0, n) in
AttributesGridView, SingleRecordReconciliationView and
DataAssociationManagementView. Verified end-to-end against a live
getting-started instance: all getting-started Playwright tests pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suggestion for modification on how the sortKeys are selected in the sample queries in Mappings

2 participants