Skip to content

fix(declarative): ignore NO_CURSOR_STATE_KEY sentinel when reconstructing parent stream state#1069

Draft
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1783576693-fix-substream-no-cursor-sentinel
Draft

fix(declarative): ignore NO_CURSOR_STATE_KEY sentinel when reconstructing parent stream state#1069
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1783576693-fix-substream-no-cursor-sentinel

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

Fixes a CDK crash at stream-construction time for manifest/low-code connectors that use a SubstreamPartitionRouter with incremental_dependency: true, where a child stream can persist the no-cursor sentinel state {"__ab_no_cursor_state_message": True} (NO_CURSOR_STATE_KEY).

ModelToComponentFactory._instantiate_parent_stream_state_manager has a fallback that reconstructs a parent stream's state from the child's state when it can't find parent_state/global_state. When the child's state dict has exactly one value, it used that value as the parent cursor value:

cursor_values = child_state.values()
if cursor_values and len(cursor_values) == 1:
    ...
    stream_state=AirbyteStateBlob({cursor_field: list(cursor_values)[0]})  # -> {cursor_field: True}

When the child previously completed with no cursor state, child_state == {"__ab_no_cursor_state_message": True}, so the fallback synthesized parent state {cursor_field: True}. Building the parent's ConcurrentCursor then calls CustomFormatConcurrentStreamStateConverter.parse_timestamp(True), which no datetime format matches, raising:

ValueError: No format in ['%Y-%m-%dT%H:%M:%S.%fZ', ...] matching True

(preceded by the warn log Trying to get_parent_state for stream ... when there are not parent state in the state).

Fix

Exclude the NO_CURSOR_STATE_KEY sentinel from the values considered by the reconstruction fallback:

cursor_values = [
    value for key, value in child_state.items() if key != NO_CURSOR_STATE_KEY
]
if cursor_values and len(cursor_values) == 1:
    ...

When the child's only state entry is the sentinel, no parent state is synthesized, so the parent cursor initializes from its configured start_datetime (equivalent to a first/empty parent sync) instead of a bogus boolean low-water-mark. This mirrors the existing sentinel handling in ConcurrentCursor.get_cursor_datetime_from_state (stream_state.get(NO_CURSOR_STATE_KEY)) and keeps real cursor state untouched.

The fix is kept at the reconstruction site (the site that produces the bad value) rather than papering over the symptom in the state-parsing layer, and does not drop or corrupt real cursor state.

Test

Added test_create_concurrent_cursor_from_perpartition_cursor_ignores_no_cursor_sentinel_child_state in unit_tests/sources/declarative/parsers/test_model_to_component_factory.py:

  • Builds a declarative substream (SubstreamPartitionRouter, incremental_dependency: true) whose incoming child state is {"__ab_no_cursor_state_message": True}.
  • Asserts building the stream/cursor no longer raises, and the parent cursor initializes to its configured start (2024-01-01T00:00:00.000000+0000) with no parent low-water-mark applied.
  • Confirmed the test fails on current main (raises the ValueError) and passes with this change.

Also ran the existing test_model_to_component_factory.py and test_concurrent_perpartitioncursor.py suites (153 passed), plus ruff check, ruff format, and mypy — all clean.

Context

This CDK bug affects any manifest/low-code connector using substream partition routers with incremental_dependency where a child stream can persist the no-cursor sentinel; the fix and test are scoped generally rather than to a specific connector.

Triaged by Devin from oncall issue airbytehq/oncall#13077 (surfaced via source-hubspot production job 93884337). The connector manifest is correct — the defect is in the CDK.

Related to https://github.com/airbytehq/oncall/issues/13077:

Link to Devin session: https://app.devin.ai/sessions/bf3e5416bb094ff3b9d896fabea7cae0

…ting parent stream state

Co-Authored-By: bot_apk <apk@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

Testing This CDK Version

You can test this version of the CDK using the following:

# Run the CLI from this branch:
uvx 'git+https://github.com/airbytehq/airbyte-python-cdk.git@devin/1783576693-fix-substream-no-cursor-sentinel#egg=airbyte-python-cdk[dev]' --help

# Update a connector to use the CDK from this branch ref:
cd airbyte-integrations/connectors/source-example
poe use-cdk-branch devin/1783576693-fix-substream-no-cursor-sentinel

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /autofix - Fixes most formatting and linting issues
  • /poetry-lock - Updates poetry.lock file
  • /test - Runs connector tests with the updated CDK
  • /prerelease - Triggers a prerelease publish with default arguments
  • /poe build - Regenerate git-committed build artifacts, such as the pydantic models which are generated from the manifest JSON schema in YAML.
  • /poe <command> - Runs any poe command in the CDK environment
📚 Show Repo Guidance

Helpful Resources

📝 Edit this welcome message.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

PyTest Results (Fast)

4 128 tests  +1   4 116 ✅ +1   7m 36s ⏱️ -5s
    1 suites ±0      12 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit 9911f40. ± Comparison against base commit dd9558c.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

PyTest Results (Full)

4 131 tests  +1   4 119 ✅ +1   11m 28s ⏱️ + 4m 13s
    1 suites ±0      12 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit 9911f40. ± Comparison against base commit dd9558c.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants