Skip to content

Commit 26d3236

Browse files
committed
feat: add details field to known exception (#13930)
## What 1. Adds an optional `details` field to `KnownExceptionInfo` 2. Parses validation details from the assist proxy and places them in the details field ## Why This allows us to show validation errors at the field level for assist ## Recommended reading order 1. `x.kt` 2. `y.kt` ## Can this PR be safely reverted and rolled back? <!-- * If you know that your be safely rolled back, check YES.* * If that is not the case (e.g. a database migration), check NO. * If unsure, leave it blank.* --> - [x] YES 💚 - [ ] NO ❌
1 parent f812e04 commit 26d3236

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

airbyte-api/server-api/src/main/openapi/config.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -12983,6 +12983,8 @@ components:
1298312983
type: array
1298412984
items:
1298512985
type: string
12986+
details:
12987+
type: object
1298612988
InvalidInputExceptionInfo:
1298712989
type: object
1298812990
required:

airbyte-commons-server/src/main/java/io/airbyte/commons/server/errors/KnownException.java

+35-5
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,78 @@
55
package io.airbyte.commons.server.errors;
66

77
import io.airbyte.api.model.generated.KnownExceptionInfo;
8+
import java.util.Map;
89
import org.apache.logging.log4j.core.util.Throwables;
910

1011
/**
1112
* Exception wrapper to handle formatting API exception outputs nicely.
1213
*/
1314
public abstract class KnownException extends RuntimeException {
1415

16+
private final Map<String, Object> details; // Add an optional details field
17+
1518
public KnownException(final String message) {
1619
super(message);
20+
this.details = null;
21+
}
22+
23+
public KnownException(final String message, final Map<String, Object> details) {
24+
super(message);
25+
this.details = details;
1726
}
1827

1928
public KnownException(final String message, final Throwable cause) {
2029
super(message, cause);
30+
this.details = null;
31+
}
32+
33+
public KnownException(final String message, final Throwable cause, final Map<String, Object> details) {
34+
super(message, cause);
35+
this.details = details;
2136
}
2237

2338
public abstract int getHttpCode();
2439

40+
public Map<String, Object> getDetails() {
41+
return details;
42+
}
43+
2544
public KnownExceptionInfo getKnownExceptionInfo() {
26-
return KnownException.infoFromThrowable(this);
45+
return KnownException.infoFromThrowable(this, details);
46+
}
47+
48+
public static KnownExceptionInfo infoFromThrowableWithMessage(final Throwable t, final String message) {
49+
return infoFromThrowableWithMessage(t, message, null); // Call the other static method with null details
2750
}
2851

2952
/**
3053
* Static factory for creating a known exception.
3154
*
3255
* @param t throwable to wrap
3356
* @param message error message
57+
* @param details additional details
3458
* @return known exception
3559
*/
36-
public static KnownExceptionInfo infoFromThrowableWithMessage(final Throwable t, final String message) {
60+
public static KnownExceptionInfo infoFromThrowableWithMessage(final Throwable t, final String message, final Map<String, Object> details) {
3761
final KnownExceptionInfo exceptionInfo = new KnownExceptionInfo()
3862
.exceptionClassName(t.getClass().getName())
3963
.message(message)
4064
.exceptionStack(Throwables.toStringList(t));
65+
4166
if (t.getCause() != null) {
42-
exceptionInfo.rootCauseExceptionClassName(t.getClass().getClass().getName());
67+
exceptionInfo.rootCauseExceptionClassName(t.getCause().getClass().getName());
4368
exceptionInfo.rootCauseExceptionStack(Throwables.toStringList(t.getCause()));
4469
}
70+
71+
if (details != null) {
72+
exceptionInfo.details(details);
73+
}
74+
4575
return exceptionInfo;
4676
}
4777

48-
public static KnownExceptionInfo infoFromThrowable(final Throwable t) {
49-
return infoFromThrowableWithMessage(t, t.getMessage());
78+
public static KnownExceptionInfo infoFromThrowable(final Throwable t, final Map<String, Object> details) {
79+
return infoFromThrowableWithMessage(t, t.getMessage(), details);
5080
}
5181

5282
}

airbyte-connector-builder-server/src/main/kotlin/io/airbyte/connector_builder/exceptions/AssistProxyException.kt

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.JsonNode
66
import io.airbyte.commons.server.errors.KnownException
77

88
class AssistProxyException(private var responseCode: Int, jsonBody: JsonNode) :
9-
KnownException(getStringFromResponse(jsonBody), getThrowableFromResponse(jsonBody)) {
9+
KnownException(getStringFromResponse(jsonBody), getThrowableFromResponse(jsonBody), getDetailsFromResponse(jsonBody)) {
1010
override fun getHttpCode(): Int {
1111
return responseCode
1212
}
@@ -19,6 +19,13 @@ fun getStringFromResponse(jsonBody: JsonNode): String {
1919
return "Unknown AI Assist error"
2020
}
2121

22+
fun getDetailsFromResponse(jsonBody: JsonNode): Map<String, Any> {
23+
if (jsonBody.has("details")) {
24+
return jsonBody.get("details").fields().asSequence().associate { it.key to it.value }
25+
}
26+
return emptyMap()
27+
}
28+
2229
fun getThrowableFromResponse(jsonBody: JsonNode): Throwable? {
2330
if (jsonBody.has("exceptionStack")) {
2431
val message = getStringFromResponse(jsonBody)
@@ -28,6 +35,7 @@ fun getThrowableFromResponse(jsonBody: JsonNode): Throwable? {
2835

2936
val throwable = Throwable(message)
3037
throwable.stackTrace = stackTrace
38+
3139
return throwable
3240
}
3341
return null

airbyte-connector-builder-server/src/main/openapi/openapi.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ components:
452452
type: array
453453
items:
454454
type: string
455+
details:
456+
type: object
455457
InvalidInputExceptionInfo:
456458
type: object
457459
required:

0 commit comments

Comments
 (0)