Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In image block, unfetchable image_url leads to message never posted instead of falling back to alt_text or fallback #1396

Open
adrian-heouairi opened this issue Nov 19, 2024 · 2 comments

Comments

@adrian-heouairi
Copy link

adrian-heouairi commented Nov 19, 2024

It seems that on chatPostMessage of a message containing an image block, the SDK tries to fetch the image located at image_url with OkHttp 4.11.0 and any other result than a successful image fetch leads to chatPostMessage failing silently and never posting the message, e.g. any response code other than HTTP 200 fails silently and the special case of an HTTP timeout leads to a SocketTimeoutException.

The Slack SDK version

Gradle versions.properties:

version.com.slack.api..slack-api-model-kotlin-extension=1.44.1
version.com.slack.api..slack-api-client-kotlin-extension=1.44.1
version.com.slack.api..bolt-socket-mode=1.44.1
version.com.slack.api..bolt-servlet=1.44.1

# Note that we also use OkHttp ourselves directly in this project
version.okhttp3=4.11.0
# slack sdk depends on this glassfish version - cannot upgrade it
version.org.glassfish.tyrus.bundles..tyrus-standalone-client=1.20

Java Runtime version

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

$ java -version
openjdk version "17.0.11" 2024-04-16 LTS
OpenJDK Runtime Environment Corretto-17.0.11.9.1 (build 17.0.11+9-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.11.9.1 (build 17.0.11+9-LTS, mixed mode, sharing)

OS info

Reproduced in local:

$ sw_vers && uname -v
ProductName:            macOS
ProductVersion:         14.7
BuildVersion:           23H124
Darwin Kernel Version 23.6.0: Wed Jul 31 20:49:39 PDT 2024; root:xnu-10063.141.1.700.5~1/RELEASE_ARM64_T6000

Note that this is also reproduced when deployed on our AWS (I don't know the architecture details).

Steps to reproduce:

  • build.gradle.kts bits that may be relevant:
id("org.jetbrains.kotlin.jvm")
id("org.springframework.boot")
implementation(Square.okHttp3)
implementation("com.slack.api:bolt-servlet:_")
implementation("com.slack.api:bolt-socket-mode:_")
implementation("com.slack.api:slack-api-model-kotlin-extension:_")
implementation("com.slack.api:slack-api-client-kotlin-extension:_")
runtimeOnly("org.glassfish.tyrus.bundles:tyrus-standalone-client:_")
  • Kotlin source code:
asyncMethodsClient.chatPostMessage {
    it.text("Something")
        .blocks(withBlocks {
            section {
                markdownText("Something")
            }
            image {
                title("Attached image")
                fallback("Attached image")
                altText("Attached image")
                imageUrl("https://www.google.com/gives_a_404.jpg")
            }
        })
        .channel(originalMessage.channelId)
        .threadTs(originalMessage.id)
}

Expected result:

Message should be posted without image and with the alt_text or fallback.

Actual result:

Message is never posted, nothing in logs for example with a 404 image URL. With a URL that times out, we get the following logs:

2024-11-08T14:18:52.060+01:00 ERROR 99547 --- [UTOR-worker-100] c.s.a.m.impl.AsyncRateLimitExecutor      : Failed to connect to chat.postMessage API (team: <obfuscated>, error: timeout)

java.net.SocketTimeoutException: timeout
	at okhttp3.internal.http2.Http2Stream$StreamTimeout.newTimeoutException(Http2Stream.kt:675) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http2.Http2Stream$StreamTimeout.exitAndThrowIfTimedOut(Http2Stream.kt:684) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http2.Http2Stream.takeHeaders(Http2Stream.kt:143) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http2.Http2ExchangeCodec.readResponseHeaders(Http2ExchangeCodec.kt:97) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.kt:110) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:93) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.11.0.jar:na]
	at com.slack.api.util.http.UserAgentInterceptor.intercept(UserAgentInterceptor.java:43) ~[slack-api-client-1.30.0.jar:1.30.0]
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201) ~[okhttp-4.11.0.jar:na]
	at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154) ~[okhttp-4.11.0.jar:na]
	at com.slack.api.util.http.SlackHttpClient.postFormWithAuthorizationHeader(SlackHttpClient.java:187) ~[slack-api-client-1.30.0.jar:1.30.0]
	at com.slack.api.util.http.SlackHttpClient.postFormWithBearerHeader(SlackHttpClient.java:174) ~[slack-api-client-1.30.0.jar:1.30.0]
	at com.slack.api.methods.impl.MethodsClientImpl.runPostFormWithToken(MethodsClientImpl.java:3162) ~[slack-api-client-1.30.0.jar:1.30.0]
	at com.slack.api.methods.impl.MethodsClientImpl.postFormWithTokenAndParseResponse(MethodsClientImpl.java:3308) ~[slack-api-client-1.30.0.jar:1.30.0]
	at com.slack.api.methods.impl.MethodsClientImpl.chatPostMessage(MethodsClientImpl.java:1588) ~[slack-api-client-1.30.0.jar:1.30.0]
	at com.slack.api.methods.impl.AsyncMethodsClientImpl.lambda$chatPostMessage$110(AsyncMethodsClientImpl.java:1351) ~[slack-api-client-1.30.0.jar:1.30.0]
	at com.slack.api.methods.impl.AsyncRateLimitExecutor.enqueueThenRun(AsyncRateLimitExecutor.java:159) ~[slack-api-client-1.30.0.jar:1.30.0]
	at com.slack.api.methods.impl.AsyncRateLimitExecutor.lambda$execute$0(AsyncRateLimitExecutor.java:77) ~[slack-api-client-1.30.0.jar:1.30.0]
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]
@adrian-heouairi adrian-heouairi changed the title In image block, incorrect image_url leads to message never posted instead of falling back to alt_text or fallback In image block, unfetchable image_url leads to message never posted instead of falling back to alt_text or fallback Nov 19, 2024
@vegeris
Copy link

vegeris commented Nov 19, 2024

Hi there,

It's the expected behaviour that the chat.postMessage API will fail with an invalid_blocks error when one attempts to send a message with an image block with an invalid image URL, due to validation on the backend

You could try using a section block with an image element, which would still send the message if the image URL is broken. (The client will show a placeholder if the image cannot be fetched)

@adrian-heouairi
Copy link
Author

Hello,

I tried (or so I think) what you suggested: section block with an image element. Here is the Kotlin code:

withBlocks {
    section {
        markdownText(text)
    }
    section {
        this@withBlocks.image {
            val title = imageTitle ?: "Attached image"
            title(title)
            fallback(title)
            altText(title)
            imageUrl("http://localhost:8091/timeout.jpg")
        }
    }
}

The message is never posted for any URL, valid, 404 or timeout. I even tried to trigger a SocketTimeoutException by using a local server that just sleeps on any GET, no exception is there, nothing in our logs.

We also tried another solution that works: using an accessory image:

withBlocks {
    section {
        markdownText(text)
        accessory {
            image(
                //imageUrl = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png",
                imageUrl = "http://localhost:8091/timeout.jpg",
                altText = "alt text",
            )
        }
    }
}

With the accessory any URL works (valid, 404, timeout) (in case of invalid URL the message is posted with a broken icon). Unfortunately it doesn't fit all use cases as the thumbnail is small.

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

No branches or pull requests

2 participants