unwrapFlightError recovers the underlying error message from an Arrow Flight / gRPC wrapper. gRPC errors stringify as "… rpc error: code = X desc = ", and the control plane further prefixes worker failures with "flight execute update: " (and similar). When the message is not Flight-wrapped
(msg string)
| 136 | // update: " (and similar). When the message is not Flight-wrapped it is returned |
| 137 | // unchanged, so this is safe to apply unconditionally before prefix matching. |
| 138 | func unwrapFlightError(msg string) string { |
| 139 | // gRPC puts the real message after the final "desc = ". |
| 140 | if idx := strings.LastIndex(msg, "desc = "); idx != -1 { |
| 141 | msg = msg[idx+len("desc = "):] |
| 142 | } |
| 143 | msg = strings.TrimSpace(msg) |
| 144 | // The worker's Flight SQL handler wraps the raw DuckDB error one more time |
| 145 | // with "failed to execute query: " / "failed to execute update: " (see |
| 146 | // duckdbservice/flight_handler.go). That sits between "desc = " and the |
| 147 | // DuckDB exception prefix, so without stripping it the HasPrefix("Catalog |
| 148 | // Error:" …) classifiers below all miss and the error falls through to |
| 149 | // XX000. Strip any one such worker prefix so classification sees the bare |
| 150 | // DuckDB message. |
| 151 | for _, p := range []string{"failed to execute update: ", "failed to execute query: "} { |
| 152 | if strings.HasPrefix(msg, p) { |
| 153 | msg = strings.TrimSpace(msg[len(p):]) |
| 154 | break |
| 155 | } |
| 156 | } |
| 157 | return msg |
| 158 | } |
| 159 | |
| 160 | // catalogErrorCode narrows a "Catalog Error: …" message to a specific SQLSTATE |
| 161 | func catalogErrorCode(msg string) string { |
no outgoing calls
no test coverage detected