Skip to content

fix(tagLabel): lenient appliedAt date deserialization#27771

Open
Khairajani wants to merge 3 commits intomainfrom
fix_taglabel_appliedat_lenient_parse
Open

fix(tagLabel): lenient appliedAt date deserialization#27771
Khairajani wants to merge 3 commits intomainfrom
fix_taglabel_appliedat_lenient_parse

Conversation

@Khairajani
Copy link
Copy Markdown
Contributor

Summary

TagLabel.appliedAt is typed java.util.Date and the global Jackson ObjectMapper is configured with SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'") — which strictly requires 6-digit fractional seconds on parse. Python clients using Pydantic emit datetimes via datetime.isoformat(), which omits the fractional part entirely when microsecond == 0 (~1/1000 odds per timestamp). The result is a payload like "2026-04-24T10:27:06Z" that the server cannot deserialize, surfacing as:

RuntimeException: Failed to convert JsonValue to target class
  caused by: Cannot deserialize value of type `java.util.Date` from String "2026-04-24T10:27:06Z":
             Unparseable date  (through reference chain: Table["columns"]→Column["tags"]→TagLabel["appliedAt"])

This was causing intermittent automator propagation failures in CI — every PATCH carrying a round-tripped appliedAt with microsecond=0 was being rejected. Same class of bug as the tag_usage.appliedAt precision fix in the 1.11.8 / 1.12.0 MySQL migrations, just on the wire side.

Fix

Register a Jackson mixin on TagLabel that deserializes appliedAt via Instant.parse(), which accepts both forms:

  • "2026-04-24T10:27:06Z" (no fractional)
  • "2026-04-24T10:27:06.918000Z" (with fractional)

Mixin is added to the global OBJECT_MAPPER before any .copy(), so all five derived mappers inherit it. No generated code is touched. Serialization is unchanged (still always emits 6-digit fractional from the global format).

Test plan

  • Added JsonUtilsTest#testTagLabelAppliedAtAcceptsBareSecondPrecision covering both forms
  • mvn compile -pl openmetadata-spec passes
  • mvn spotless:apply clean
  • CI integration tests

@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@Khairajani Khairajani added the safe to test Add this label to run secure Github workflows on PRs label Apr 27, 2026
Accept ISO-8601 datetimes with or without fractional seconds for
TagLabel.appliedAt. Python clients omit fractional when a datetime's
microsecond is zero, emitting strings like "2026-04-24T10:27:06Z" that
the strict global SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'")
rejects, causing PATCH operations to fail with "Failed to convert
JsonValue to target class".
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 27, 2026

🔴 Playwright Results — 16 failure(s), 16 flaky

✅ 3942 passed · ❌ 16 failed · 🟡 16 flaky · ⏭️ 86 skipped

Shard Passed Failed Flaky Skipped
✅ Shard 1 299 0 0 4
🟡 Shard 2 740 0 4 8
🟡 Shard 3 743 0 5 7
🔴 Shard 4 756 1 2 18
🔴 Shard 5 675 10 2 41
🔴 Shard 6 729 5 3 8

Genuine Failures (failed on all attempts)

Pages/Entity.spec.ts › Tag Add, Update and Remove for child entities (shard 4)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  locator('[data-row-key="snowflake_task"]').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for locator('[data-row-key="snowflake_task"]').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for table (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for dashboard (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for pipeline (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for topic (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for database (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for databaseSchema (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for dashboardDataModel (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for mlmodel (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for container (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for searchIndex (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    19 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    19 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    19 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

🟡 16 flaky test(s) (passed on retry)
  • Features/ActivityAPI.spec.ts › Activity event is created when description is updated (shard 2, 1 retry)
  • Features/ActivityAPI.spec.ts › Activity event is created when owner is added (shard 2, 1 retry)
  • Features/Glossary/GlossaryWorkflow.spec.ts › should display correct status badge color and icon (shard 2, 2 retries)
  • Features/Glossary/GlossaryWorkflow.spec.ts › should start term as Draft when glossary has reviewers (shard 2, 2 retries)
  • Features/OntologyExplorer.spec.ts › clicking a term node opens the entity summary panel without a permission error (shard 3, 1 retry)
  • Features/RTL.spec.ts › Verify Following widget functionality (shard 3, 1 retry)
  • Features/Table.spec.ts › Tags term should be consistent for search (shard 3, 1 retry)
  • Features/UserProfileOnlineStatus.spec.ts › Should show online status badge on user profile for active users (shard 3, 1 retry)
  • Flow/PersonaFlow.spec.ts › Set default persona for team should work properly (shard 3, 1 retry)
  • Pages/DataContractsSemanticRules.spec.ts › Validate Description Rule Is_Not_Set (shard 4, 1 retry)
  • Pages/Entity.spec.ts › Tier Add, Update and Remove (shard 4, 1 retry)
  • Pages/EntityDataConsumer.spec.ts › Glossary Term Add, Update and Remove for child entities (shard 5, 1 retry)
  • Pages/EntityDataSteward.spec.ts › Glossary Term Add, Update and Remove for child entities (shard 5, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify lineage schema filter selection (shard 6, 1 retry)
  • Pages/Lineage/LineageRightPanel.spec.ts › Verify custom properties tab IS visible for supported type: searchIndex (shard 6, 1 retry)
  • Pages/ProfilerConfigurationPage.spec.ts › Admin user (shard 6, 1 retry)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

@gitar-bot
Copy link
Copy Markdown

gitar-bot Bot commented Apr 27, 2026

Code Review ✅ Approved 1 resolved / 1 findings

Updates the LenientIsoDateDeserializer to handle DateTimeParseException errors, ensuring robust deserialization of appliedAt dates. No further issues found.

✅ 1 resolved
Edge Case: LenientIsoDateDeserializer doesn't wrap DateTimeParseException

📄 openmetadata-spec/src/main/java/org/openmetadata/schema/utils/JsonUtils.java:912-918
Instant.parse(value) throws an unchecked DateTimeParseException for malformed input. While Jackson's infrastructure will catch it and surface an error, wrapping it in a ctxt.handleUnexpectedToken(...) or JsonMappingException would produce a cleaner, more consistent error message with the JSON path context (e.g., through reference chain: ...TagLabel["appliedAt"]) rather than an unwrapped runtime exception.

In practice this is low-impact because Jackson does catch RuntimeException during deserialization and re-wraps it, but explicit handling is the idiomatic Jackson pattern and gives better diagnostics.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant