Skip to content

fix: escape periods in attribute keys during flatten/unflatten#3800

Closed
deepshekhardas wants to merge 1 commit into
triggerdotdev:mainfrom
deepshekhardas:fix/1510-period-keys-attribute-flattening
Closed

fix: escape periods in attribute keys during flatten/unflatten#3800
deepshekhardas wants to merge 1 commit into
triggerdotdev:mainfrom
deepshekhardas:fix/1510-period-keys-attribute-flattening

Conversation

@deepshekhardas
Copy link
Copy Markdown

Fixes #1510

Object keys containing periods (e.g. { "Key 0.002mm": 31.4 }) were incorrectly split on the . delimiter during flattening, causing dashboard display corruption.

Fix: Escape . in object keys with $@dot sentinel during flatten and unescape during unflatten. This is consistent with the existing $@null(( and $@circular(( sentinel pattern.

Changes:

  • flattenAttributes.ts: escape dots in non-array keys during flatten
  • unflattenAttributes(): unescape sentinel back to . after splitting
  • Added 3 test cases for period-containing keys

Object keys containing periods (e.g. 'Key 0.002mm') were incorrectly
split on the '.' delimiter during flatten/unflatten, causing data
corruption in the dashboard logs view. Escape dots with \$@dot sentinel
during flattening and unescape during unflattening.

Fixes triggerdotdev#1510
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 2, 2026

⚠️ No Changeset found

Latest commit: f515902

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

Hi @deepshekhardas, thanks for your interest in contributing!

This project requires that pull request authors are vouched, and you are not in the list of vouched users.

This PR will be closed automatically. See https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md for more details.

@github-actions github-actions Bot closed this Jun 2, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 05b89fb5-833f-402c-af2c-c5c2f69cb31e

📥 Commits

Reviewing files that changed from the base of the PR and between 2dd9f37 and f515902.

📒 Files selected for processing (2)
  • packages/core/src/v3/utils/flattenAttributes.ts
  • packages/core/test/flattenAttributes.test.ts

Walkthrough

This PR modifies the flattenAttributes and unflattenAttributes utility functions to properly escape and unescape dot characters (.) in object keys. A new DOT_ESCAPE marker is introduced to represent escaped dots in flattened paths. During flattening, dots in non-array keys are replaced with the escape marker while array index notation is preserved. During unflattening, the escape marker is converted back to dots before parsing bracketed segments, ensuring that keys containing literal periods round-trip correctly through the flatten/unflatten cycle. Three test cases verify the behavior with single periods, multiple periods, and nested keys.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Map keys with dots are not escaped (pre-existing inconsistency)

At line 121, Map string keys are interpolated directly into the prefix without dot escaping: this.#processValue(value, \${prefix || "map"}.${keyStr}`, depth). This is inconsistent with the new escaping for regular object keys at line 204 (key.replace(/./g, DOT_ESCAPE)). If a Map has a key like "a.b"`, the dot won't be escaped, leading to incorrect unflattening. However, this is a pre-existing issue — Map key handling was already inconsistent before this PR, and Maps are a relatively niche case for OTEL attributes. Not filing as a bug since it's pre-existing, but worth noting for completeness.

(Refers to lines 120-121)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +204 to +205
const escapedKey = Array.isArray(obj) ? `[${key}]` : key.replace(/\./g, DOT_ESCAPE);
const newPrefix = `${prefix ? `${prefix}.` : ""}${escapedKey}`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Round-trip data corruption for keys naturally containing the $@dot escape sequence

The escape sequence $@dot is never itself escaped during flattening, so keys that naturally contain the literal string $@dot are silently corrupted during round-trip. During flattenAttributes, key.replace(/\./g, DOT_ESCAPE) won't modify a key like "a$@dotb" (no dots to replace), so it stays as "a$@dotb". But during unflattenAttributes at flattenAttributes.ts:285, part.split(DOT_ESCAPE).join(".") transforms "a$@dotb" into "a.b", corrupting the key. For example: {"a$@dotb": 1} → flatten → {"a$@dotb": 1} → unflatten → {"a.b": 1}. This is a fundamental flaw in the escape mechanism — proper escaping requires that the escape sequence itself be escaped (e.g., $@dot$@dot$@dot or a different sentinel).

Prompt for agents
The escape mechanism is not reversible because the escape sequence itself is not escaped. When flattenAttributes encounters a key like "a$@dotb" (no dots), it passes it through unchanged. But unflattenAttributes unconditionally replaces all occurrences of $@dot with dots, corrupting the key to "a.b".

To fix this properly, you need a two-phase escape:
1. First escape any existing occurrences of the escape marker (e.g., replace "$@dot" with "$@dot$@dot" or use a dedicated escape-of-escape like "$@esc"), THEN replace dots with the escape marker.
2. In unflattenAttributes, reverse the process: first unescape the dot marker, then unescape the escape-of-escape marker.

Alternatively, choose an escape sequence that is guaranteed not to collide (e.g., a longer/more unique sentinel), though this only reduces probability rather than eliminating the issue.

Files to update:
- packages/core/src/v3/utils/flattenAttributes.ts: both the escaping in doFlatten (line 204) and unescaping in unflattenAttributes (line 285)
- packages/core/test/flattenAttributes.test.ts: add a test for keys containing the escape sequence
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


export const NULL_SENTINEL = "$@null((";
export const CIRCULAR_REFERENCE_SENTINEL = "$@circular((";
const DOT_ESCAPE = "$@dot";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Escape sequence $@dot starts with $, causing keys beginning with . to be silently dropped by removePrivateProperties

The $@dot escape sequence starts with $, which conflicts with the removePrivateProperties filter at apps/webapp/app/v3/eventRepository/common.server.ts:155 that drops all keys starting with $. When a user has an object key starting with . (e.g., {".foo": "bar"}), flattenAttributes escapes it to "$@dotfoo". This key is stored in the database. When later read back, removePrivateProperties sees the key starts with $ and filters it out before unflattenAttributes ever runs. The property is silently lost. Before this PR, a key like ".foo" would be stored as ".foo" and would not be filtered (it doesn't start with $). While keys starting with . are uncommon, this is a silent data loss regression.

Affected data flow
  1. User logs {".hidden": "value"} from a task
  2. SDK flattens to {"$@dothidden": "value"}
  3. Server stores $@dothidden as attribute key
  4. On read, removePrivateProperties filters it out (starts with $)
  5. Property is silently lost from span display
Prompt for agents
The escape sequence $@dot starts with $, which collides with the convention in removePrivateProperties (apps/webapp/app/v3/eventRepository/common.server.ts:155) that filters out all attribute keys starting with $. This means any user object key starting with a literal dot (.) will be escaped to a key starting with $@dot, which then gets silently dropped.

The simplest fix is to choose an escape sequence that does NOT start with $ or ctx. — the two prefixes filtered by removePrivateProperties. For example, using __dot__ or ~dot~ or any sequence that doesn't start with a character used for internal attribute prefixes.

Files to update:
- packages/core/src/v3/utils/flattenAttributes.ts: change the DOT_ESCAPE constant (line 5)
- packages/core/test/flattenAttributes.test.ts: update test expectations to match new escape sequence
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

[TRI-4123] Logging objects with keys with periods in doesn't render properly in the UI

1 participant