Skip to content

fix(step): using a Step instance as a decorator always raises TypeError - #3032

Open
Anai-Guo wants to merge 1 commit into
Chainlit:mainfrom
Anai-Guo:fix-step-instance-decorator
Open

fix(step): using a Step instance as a decorator always raises TypeError#3032
Anai-Guo wants to merge 1 commit into
Chainlit:mainfrom
Anai-Guo:fix-step-instance-decorator

Conversation

@Anai-Guo

@Anai-Guo Anai-Guo commented Aug 29, 2026

Copy link
Copy Markdown

The bug

Step.__call__ lets a Step instance be used as a decorator. It forwards thread_id to the step() decorator factory:

backend/chainlit/step.py:447-455

def __call__(self, func):
    return step(
        original_function=func,
        type=self.type,
        name=self.name,
        id=self.id,
        parent_id=self.parent_id,
        thread_id=self.thread_id,   # <-- step() has no such parameter
    )

…but step() does not declare thread_id. So any use of a Step instance as a decorator raises before the wrapped function ever runs:

TypeError: step() got an unexpected keyword argument 'thread_id'

Step.__init__ does accept thread_id (and tests/test_step.py::test_step_with_custom_thread_id already covers it there), so the parameter is real everywhere except on the decorator path that tries to propagate it.

The fix

Add thread_id: Optional[str] = None to step() and pass it to the Step(...) it constructs — in both the async and the sync wrapper, so the two branches stay symmetric. Step.__init__ already does self.thread_id = thread_id or context.session.thread_id, so the default None preserves today's behaviour for every existing caller.

+3 lines in step.py.

Tests

Two tests added to TestStepDecorator:

  • test_step_instance_used_as_decorator — the crash itself: @Step(name=..., type="tool") on an async function.
  • test_step_decorator_forwards_thread_id@step(thread_id=...) actually reaches the Step that gets created, so the new parameter is wired up rather than merely accepted.

Both fail on main with the exact TypeError above, and pass with the fix:

# before
tests/test_step.py::TestStepDecorator::test_step_instance_used_as_decorator
E  TypeError: step() got an unexpected keyword argument 'thread_id'  (chainlit/step.py:449)
tests/test_step.py::TestStepDecorator::test_step_decorator_forwards_thread_id
E  TypeError: step() got an unexpected keyword argument 'thread_id'
2 failed

# after
47 passed, 3 warnings in 0.53s     # 45 pre-existing + 2 new

ruff check and ruff format --check are clean on both files using the repo's root pyproject.toml config.

🤖 Generated with Claude Code


Summary by cubic

Fixes using a Step instance as a decorator, which always raised TypeError because step() didn't accept thread_id; now it does and forwards it, so @Step(...) works again. Adds tests for decorator usage and thread_id forwarding.

Written for commit f301816. Summary will update on new commits.

Review in cubic

Step.__call__ forwards thread_id=self.thread_id to step(), but step() had no
thread_id parameter, so decorating a function with a Step instance
(@step(name=...)) always raised TypeError before the wrapped function ran.

Add thread_id to step() and pass it through to the Step it builds in both the
async and sync wrappers, matching the parameter Step.__init__ already accepts.
@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. backend Pertains to the Python backend. bug Something isn't working unit-tests Has unit tests. labels Aug 29, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/chainlit/step.py">

<violation number="1" location="backend/chainlit/step.py:113">
P3: The sync decorator path now forwards `thread_id` to `Step(...)` but has no test. Since the PR explicitly aims for sync/async symmetry and only exercises async in the new tests, add a sync-variant of `test_step_decorator_forwards_thread_id` (a plain `def` wrapped with `@step(thread_id=...)`) to cover `sync_wrapper`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread backend/chainlit/step.py
name=name,
id=id,
parent_id=parent_id,
thread_id=thread_id,

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.

P3: The sync decorator path now forwards thread_id to Step(...) but has no test. Since the PR explicitly aims for sync/async symmetry and only exercises async in the new tests, add a sync-variant of test_step_decorator_forwards_thread_id (a plain def wrapped with @step(thread_id=...)) to cover sync_wrapper.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/chainlit/step.py, line 113:

<comment>The sync decorator path now forwards `thread_id` to `Step(...)` but has no test. Since the PR explicitly aims for sync/async symmetry and only exercises async in the new tests, add a sync-variant of `test_step_decorator_forwards_thread_id` (a plain `def` wrapped with `@step(thread_id=...)`) to cover `sync_wrapper`.</comment>

<file context>
@@ -109,6 +110,7 @@ async def async_wrapper(*args, **kwargs):
                     name=name,
                     id=id,
                     parent_id=parent_id,
+                    thread_id=thread_id,
                     tags=tags,
                     language=language,
</file context>

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

Labels

backend Pertains to the Python backend. bug Something isn't working size:XS This PR changes 0-9 lines, ignoring generated files. unit-tests Has unit tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant