On_session_end event doesn't work

I have this error and can’t record session_report to db

message=error while executing the on_session_end callback Traceback (most recent call last): File "/app/src/x/infrastructure/events/report.py", line 12, in on_session_end report = ctx.make_session_report() ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/.venv/lib/python3.12/site-packages/livekit/agents/job.py", line 328, in make_session_report raise RuntimeError("Cannot prepare report, no AgentSession was found") RuntimeError: Cannot prepare report, no AgentSession was found The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/app/.venv/lib/python3.12/site-packages/livekit/agents/ipc/job_proc_lazy_main.py", line 357, in _run_job_task await self._session_end_fnc(self._job_ctx) File "/app/src/x/infrastructure/events/report.py", line 14, in on_session_end raise RuntimeError( RuntimeError: No session report available (session may not have started)
level=ERROR
name=livekit.agents
exc_info=Traceback (most recent call last): File "/app/src/x/infrastructure/events/report.py", line 12, in on_session_end report = ctx.make_session_report() ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/.venv/lib/python3.12/site-packages/livekit/agents/job.py", line 328, in make_session_report raise RuntimeError("Cannot prepare report, no AgentSession was found") RuntimeError: Cannot prepare report, no AgentSession was found The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/app/.venv/lib/python3.12/site-packages/livekit/agents/ipc/job_proc_lazy_main.py", line 357, in _run_job_task await self._session_end_fnc(self._job_ctx) File "/app/src/x/infrastructure/events/report.py", line 14, in on_session_end raise RuntimeError( RuntimeError: No session report available (session may not have started)
pid=41
job_id=AJ_MrHPQz67LU3A
room_id=RM_d4E4XnJBKJ7x
timestamp=2026-08-21T18:14:24.634903+00:00```
@server.rtc_session(*agent_name*=*"XAssistant"*, *on_session_end*=on_session_end)

async def x_agent(ctx: JobContext):



    metadata = json.loads(ctx.job.metadata)



    try:

        metadata\[*"company_name"*\] = metadata\[*"company_name"*\].strip()

        metadata\[*"pool_name"*\] = metadata\[*"pool_name"*\].strip()

    except Exception as e:

        raise ValueError(

            *"Invalid metadata: company_name and pool_name are required"*

        ) from e



    async with session_scope() as db:

        pool = await db.scalar(

            select(QuestionPoolTable).where(

                QuestionPoolTable.company_name == metadata\[*"company_name"*\],

                QuestionPoolTable.pool_name == metadata\[*"pool_name"*\],

            )

        )

        if pool is None:

            raise ValueError(*"Question pool not found"*)

        questions, rubrics = pool.questions, pool.rubrics



        sess = XSession(

            *session_id*=ctx.room.name,

            *company_name*=metadata\[*"company_name"*\],

            *pool_name*=metadata\[*"pool_name"*\],

        )

        await save_to_db(db, sess)




    session = await create_x_session(tts, llm, stt)



    @session.on(*"conversation_item_added"*)

    async def on_conversation_item_added(ev: ConversationItemAddedEvent):

        await collect_metrics_event(ev, *session_id*=ctx.room.name)

        await collect_message_event(ev, *session_id*=ctx.room.name)




    await session.start(

        *room*=ctx.room,

        *agent*=XAssistant(questions, rubrics),

    )

    await session.say(

        *f"Welcome to today's* {metadata\[*'pool_name'*\]} *x at "*

        *f"*{metadata\[*'company_name'*\]} *are you ready for x?"*

    )



if \__name_\_ == *"\__main_\_"*:

    cli.run_app(server)
async def on_session_end(ctx: JobContext) -> None:

    try:

        report = ctx.make_session_report()

    except Exception as e:

        raise RuntimeError(

            *"No session report available (session may not have started)"*

        ) from e



    report_dict = report.to_dict()



    try:

        async with session_scope() as db:

            new_report = SessionReport(             

                *report_json*=report_dict,            

            )



            await save_to_db(db, new_report )

            

            logger.info(*"Session report for %s saved to PostgreSQL (ID: %s)"*, 

                       ctx.room.name, new_report.id)



    except Exception as e:

        raise RuntimeError(*f"Failed to save session report to DB:* {e}*"*) from e

This isn’t the callback failing it’s telling you the job ended before session.start() ever ran. The session only registers itself on the job context inside start(), and on_session_end fires on every job teardown, including jobs that crashed earlier. So make_session_report() is right to raise here.

Your entrypoint has two raise ValueError paths before session.start() the metadata .strip() and “Question pool not found”. The real error will be in your logs just above this one, and that’s the one to chase. Worth guarding the callback either way, since the framework does the same internally:

  async def on_session_end(ctx: JobContext) -> None:
      try:
          report = ctx.make_session_report()
      except RuntimeError:
          logger.info("no AgentSession for job %s, nothing to report", ctx.job.id)
          return

Also, your except Exception: raise RuntimeError(“No session report available…”) is replacing the original exception with a less specific one dropping it will make the next failure easier to read.

To add to @abidullahcs.uk 's point, I can’t see any sessions for your project. Are you able to successfully run through the voice agent quickstart: Voice AI quickstart | LiveKit Documentation

Yes I am able to run the session don’t have problem. Thank you for your help.