S3 Egress Error — "Start Signal Not Received"

Hi LiveKit Support Team,

I am encountering frequent errors with S3 egress on my account. I am consistently getting the following error:

“Start signal not received”
egress Id: EG_uKPkSJRYhHSD

This is happening across multiple sessions and I am not sure what is causing it. Could you please help me understand the root cause of this error and suggest a fix?

Any guidance or solution would be greatly appreciated.

Thank you,
Vishal Maurya
TapTalent

Looks like the Egress is never becoming active.

That Egress ID is associated with room RM_8SWsMZSeCZJp and I see that there are no publishing participants in the room. Egress needs a participant track to start recording, so that would explain why ‘start signal not received’.

If I look at another one of your failed egresses, e.g. EG_5ZkTNiyR2bqn, I see a similar pattern

I have made a code change — instead of attaching egress after room creation, I am now using Auto Egress which attaches it atomically at the time of room creation. Could you please confirm if this approach will resolve the issue?

Here is my updated implementation:

const output = new EncodedFileOutput({
fileType: EncodedFileType.MP3,       // good format for speech
filepath: interview-recordings/${roomName}.mp3,
output: {
case: “s3”,
value: new S3Upload({
accessKey: INTERVIEW_BUCKET_AWS_ACCESS_KEY_ID,
secret: INTERVIEW_BUCKET_AWS_SECRET_ACCESS_KEY,
bucket: “taptalent-interview-recordings”,
region: region,
forcePathStyle: true,
}),
},
});

// Create Room and Auto-Attach Egress in ONE atomic call
await roomService.createRoom({
name: roomName,
maxParticipants: 3,
departureTimeout: 60,
// Auto Egress: Automatically starts recording when room is active
egress: {
room: {
roomName: roomName,
audioOnly: true,
audioMixing: AudioMixing.DUAL_CHANNEL_AGENT, // agent-left, others-right
fileOutputs: [output],
},
},
});

Does this change fix the “Start Signal Not Received” error? Please let me know if any further changes are needed.

I don’t think so because auto egress will start when the room is created, but if no publishing participants join you would still see ‘Start Signal Not Received’

Let me explain my current setup in detail:

My Setup:

  1. I create a room with Auto Egress enabled on the backend

  2. The room token is passed to the frontend

  3. On the frontend, the candidate joins the room using the <LiveKitRoom> component as follows:

    <LiveKitRoom
    serverUrl={liveKitUrl}
    token={token}
    connect={true}
    audio={audioOptions}
    video={false}
    onConnected={handleConnected}
    onDisconnected={handleDisconnected}
    onError={handleError}
    onMediaDeviceFailure={handleMediaDeviceFailure}

My Questions:

  • What could be the possible root cause of this error in my setup?

  • How can I resolve this issue? (very important)

  • How can we get or log the exact error

The question is why is the participant not joining the room I believe. I have some thoughts:

  • Double check the token you are sending to the client, is it valid? Does it contain the roomJoin permission? There is an UNOFFICIAL token validator here: LiveKit Token Validator
  • Is the room specified int he egress creation call the same as the room contained within the token
  • Do you see anything in the onError callback? What about onConnected?

How can we get or log the exact error

This is on your client, so logs would be client logs and dependant on the platform. For JavaScript for example, these will be debug logs (this field guide has extra info); For Android, logs will be adb etc.

Below is my code of room token generation.
Can you please check and let me know about any issues?

const enableRecording = async ({ roomName, testInfo }) => {

  try {

const { testId, inviteId, email, companyId, candidateName } =

testInfo ?? {};




// 1. Prepare your recording output exactly like before

// NOTE: Depending on your SDK version, "value" requires a "new S3Upload()" wrapper

const output = new EncodedFileOutput({

fileType: EncodedFileType.MP3, // good source format for speech

filepath: `interview-recordings/${roomName}.mp3`,

output: {

case: "s3",

value: new S3Upload({ 

accessKey: INTERVIEW_BUCKET_AWS_ACCESS_KEY_ID,

secret: INTERVIEW_BUCKET_AWS_SECRET_ACCESS_KEY,

bucket: "taptalent-interview-recordings",

region: region,

forcePathStyle: true,

        }),

      },

    });




// 2. Create Room and Auto-Attach Egress in ONE atomic call

await roomService

      .createRoom({

name: roomName,

maxParticipants: 3,

departureTimeout: 60,

// 👇 LiveKit Auto-Egress: Automatically records when the room is active

egress: {

room: {

roomName: roomName,

audioOnly: true,

audioMixing: AudioMixing.DUAL_CHANNEL_AGENT, // agent-left, others-right

fileOutputs:[output], // Attach your S3 Output here

          },

        },

      })

      .catch(async (err) => {

console.log(

`LIVEKIT ROOM CREATION/EGRESS ERROR testToken ${inviteId} \n Error : ${JSON.stringify(err)}`

        );

const msg = `testId : ${testId} \n testToken : ${inviteId} \n email : ${email} \n companyId : ${companyId} \n candidateName : ${candidateName} \n error : ${JSON.stringify(err)}`;

await slackSendMessage({

message: msg,

notificationHeading: `*LIVEKIT ROOM CREATION ERROR [${environment}]*`,

type: "ERROR",

webhookUrl: slackAIInterviewProviderError,

        });

throw err;

      });




console.log(`Created Room ${roomName} successfully with Auto-Recording attached.`);

  } catch (error) {

console.log(`Failed to enable recording for room ${roomName}: ${error}`);

throw error;

  }

};

const handleCreateRoom = async ({
initialPrompt,
uniqueRoomId,
testInfo,
voiceId,
voiceProvider,
language,
duration,
}) => {
const roomName = uniqueRoomId ?? taptalent-${Date.now()};

const agentName = “interview-agent”;
const participantName = testInfo?.candidateName ?? “”;
await enableRecording({ roomName, testInfo });

// 3. EXPLICITLY Dispatch the Agent
// Since the room is already created by the recorder, we must manually summon the agent.
console.log(“Dispatching AI Agent…”);

try {
const agentDispatchClient = new AgentDispatchClient(
LIVEKIT_URL,
LIVEKIT_API_KEY,
LIVEKIT_API_SECRET,
);
await agentDispatchClient.createDispatch(roomName, agentName, {
metadata,
});
} catch (error) {
console.error(“Failed to dispatch agent:”, error);
throw error;
}

const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, {
identity: participantName,
name: participantName,
ttl: duration * 60 + 300, // duration in minutes for token validity + 5 minutes buffer
});
at.addGrant({ roomJoin: true, room: roomName });

const token = await at.toJwt();
return { liveKitUrl: LIVEKIT_URL, token, roomName, agentName };
};

Does this give the answer of these question

  1. Double check the token you are sending to the client, is it valid? Does it contain the roomJoin permission?
  2. Is the room specified int he egress creation call the same as the room contained within the token