@@ -2161,14 +2161,16 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
21612161 _message : AdapterPostableMessage
21622162 ) : Promise < RawMessage < unknown > > {
21632163 const message = await this . resolveMessageMentions ( _message , threadId ) ;
2164- const { channel, threadTs } = this . decodeThreadId ( threadId ) ;
2164+ const { channel, threadTs : rawThreadTs } = this . decodeThreadId ( threadId ) ;
2165+ // Normalize empty threadTs to undefined to avoid Slack API "invalid_thread_ts" errors
2166+ const threadTs = rawThreadTs || undefined ;
21652167
21662168 try {
21672169 // Check for files to upload
21682170 const files = extractFiles ( message ) ;
21692171 if ( files . length > 0 ) {
21702172 // Upload files first (they're shared to the channel automatically)
2171- await this . uploadFiles ( files , channel , threadTs || undefined ) ;
2173+ await this . uploadFiles ( files , channel , threadTs ) ;
21722174
21732175 // If message only has files (no text/card), return early
21742176 const hasText =
@@ -2302,7 +2304,8 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
23022304 _message : AdapterPostableMessage
23032305 ) : Promise < EphemeralMessage > {
23042306 const message = await this . resolveMessageMentions ( _message , threadId ) ;
2305- const { channel, threadTs } = this . decodeThreadId ( threadId ) ;
2307+ const { channel, threadTs : rawThreadTs } = this . decodeThreadId ( threadId ) ;
2308+ const threadTs = rawThreadTs || undefined ;
23062309
23072310 try {
23082311 // Check if message contains a card
@@ -2323,7 +2326,7 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
23232326 const result = await this . client . chat . postEphemeral (
23242327 this . withToken ( {
23252328 channel,
2326- thread_ts : threadTs || undefined ,
2329+ thread_ts : threadTs ,
23272330 user : userId ,
23282331 text : fallbackText ,
23292332 blocks,
@@ -2356,7 +2359,7 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
23562359 const result = await this . client . chat . postEphemeral (
23572360 this . withToken ( {
23582361 channel,
2359- thread_ts : threadTs || undefined ,
2362+ thread_ts : threadTs ,
23602363 user : userId ,
23612364 text : tableResult . text ,
23622365 blocks : tableResult . blocks ,
@@ -2392,7 +2395,7 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
23922395 const result = await this . client . chat . postEphemeral (
23932396 this . withToken ( {
23942397 channel,
2395- thread_ts : threadTs || undefined ,
2398+ thread_ts : threadTs ,
23962399 user : userId ,
23972400 text,
23982401 } )
@@ -2420,7 +2423,8 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
24202423 options : { postAt : Date }
24212424 ) : Promise < ScheduledMessage > {
24222425 const message = await this . resolveMessageMentions ( _message , threadId ) ;
2423- const { channel, threadTs } = this . decodeThreadId ( threadId ) ;
2426+ const { channel, threadTs : rawThreadTs } = this . decodeThreadId ( threadId ) ;
2427+ const threadTs = rawThreadTs || undefined ;
24242428 const postAtUnix = Math . floor ( options . postAt . getTime ( ) / 1000 ) ;
24252429
24262430 if ( postAtUnix <= Math . floor ( Date . now ( ) / 1000 ) ) {
@@ -2456,7 +2460,7 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
24562460 const result = await this . client . chat . scheduleMessage ( {
24572461 token,
24582462 channel,
2459- thread_ts : threadTs || undefined ,
2463+ thread_ts : threadTs ,
24602464 post_at : postAtUnix ,
24612465 text : fallbackText ,
24622466 blocks,
@@ -2498,7 +2502,7 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
24982502 const result = await this . client . chat . scheduleMessage ( {
24992503 token,
25002504 channel,
2501- thread_ts : threadTs || undefined ,
2505+ thread_ts : threadTs ,
25022506 post_at : postAtUnix ,
25032507 text,
25042508 unfurl_links : false ,
@@ -2929,7 +2933,16 @@ export class SlackAdapter implements Adapter<SlackThreadId, unknown> {
29292933 "Slack streaming requires recipientUserId and recipientTeamId in options"
29302934 ) ;
29312935 }
2932- const { channel, threadTs } = this . decodeThreadId ( threadId ) ;
2936+ const { channel, threadTs : rawThreadTs } = this . decodeThreadId ( threadId ) ;
2937+ // Normalize empty threadTs to undefined to avoid Slack API "invalid_thread_ts" errors
2938+ const threadTs = rawThreadTs || undefined ;
2939+ if ( ! threadTs ) {
2940+ this . logger . debug ( "Slack: stream skipped - no thread context" ) ;
2941+ throw new ValidationError (
2942+ "slack" ,
2943+ "Slack streaming requires a valid thread context (non-empty threadTs)"
2944+ ) ;
2945+ }
29332946 this . logger . debug ( "Slack: starting stream" , { channel, threadTs } ) ;
29342947
29352948 const token = this . getToken ( ) ;
0 commit comments