tries to disable quarantined aws keys
This commit is contained in:
parent
994b30dcce
commit
edc0d094e2
|
@ -65,7 +65,7 @@ type ErrorGeneratorOptions = {
|
|||
format: APIFormat | "unknown";
|
||||
title: string;
|
||||
message: string;
|
||||
obj?: object;
|
||||
obj?: Record<string, any>;
|
||||
reqId: string | number | object;
|
||||
model?: string;
|
||||
statusCode?: number;
|
||||
|
@ -95,6 +95,23 @@ export function tryInferFormat(body: any): APIFormat | "unknown" {
|
|||
return "unknown";
|
||||
}
|
||||
|
||||
// avoid leaking upstream hostname on dns resolution error
|
||||
function redactHostname(options: ErrorGeneratorOptions): ErrorGeneratorOptions {
|
||||
if (!options.message.includes("getaddrinfo")) return options;
|
||||
|
||||
const redacted = { ...options };
|
||||
redacted.message = "Could not resolve hostname";
|
||||
|
||||
if (typeof redacted.obj?.error === "object") {
|
||||
redacted.obj = {
|
||||
...redacted.obj,
|
||||
error: { message: "Could not resolve hostname" },
|
||||
};
|
||||
}
|
||||
|
||||
return redacted;
|
||||
}
|
||||
|
||||
export function sendErrorToClient({
|
||||
options,
|
||||
req,
|
||||
|
@ -104,27 +121,26 @@ export function sendErrorToClient({
|
|||
req: express.Request;
|
||||
res: express.Response;
|
||||
}) {
|
||||
const { format: inputFormat } = options;
|
||||
const redactedOpts = redactHostname(options);
|
||||
const { format: inputFormat } = redactedOpts;
|
||||
|
||||
// This is an error thrown before we know the format of the request, so we
|
||||
// can't send a response in the format the client expects.
|
||||
const format =
|
||||
inputFormat === "unknown" ? tryInferFormat(req.body) : inputFormat;
|
||||
if (format === "unknown") {
|
||||
return res.status(options.statusCode || 400).json({
|
||||
error: options.message,
|
||||
details: options.obj,
|
||||
return res.status(redactedOpts.statusCode || 400).json({
|
||||
error: redactedOpts.message,
|
||||
details: redactedOpts.obj,
|
||||
});
|
||||
}
|
||||
|
||||
const completion = buildSpoofedCompletion({ ...options, format });
|
||||
const event = buildSpoofedSSE({ ...options, format });
|
||||
const completion = buildSpoofedCompletion({ ...redactedOpts, format });
|
||||
const event = buildSpoofedSSE({ ...redactedOpts, format });
|
||||
const isStreaming =
|
||||
req.isStreaming || req.body.stream === true || req.body.stream === "true";
|
||||
|
||||
if (!res.headersSent) {
|
||||
res.setHeader("x-oai-proxy-error", options.title);
|
||||
res.setHeader("x-oai-proxy-error-status", options.statusCode || 500);
|
||||
res.setHeader("x-oai-proxy-error", redactedOpts.title);
|
||||
res.setHeader("x-oai-proxy-error-status", redactedOpts.statusCode || 500);
|
||||
}
|
||||
|
||||
if (isStreaming) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* This file is fucking horrendous, sorry */
|
||||
// TODO: extract all per-service error response handling into its own modules
|
||||
import { Request, Response } from "express";
|
||||
import * as http from "http";
|
||||
import { config } from "../../../config";
|
||||
|
@ -225,7 +226,7 @@ const handleUpstreamErrors: ProxyResHandlerWithBody = async (
|
|||
break;
|
||||
case "anthropic":
|
||||
case "aws":
|
||||
await handleAnthropicBadRequestError(req, errorPayload);
|
||||
await handleAnthropicAwsBadRequestError(req, errorPayload);
|
||||
break;
|
||||
default:
|
||||
assertNever(service);
|
||||
|
@ -247,7 +248,9 @@ const handleUpstreamErrors: ProxyResHandlerWithBody = async (
|
|||
);
|
||||
keyPool.update(req.key!, { allowsMultimodality: false });
|
||||
await reenqueueRequest(req);
|
||||
throw new RetryableError("Claude request re-enqueued because key does not support multimodality.");
|
||||
throw new RetryableError(
|
||||
"Claude request re-enqueued because key does not support multimodality."
|
||||
);
|
||||
} else {
|
||||
keyPool.disable(req.key!, "revoked");
|
||||
errorPayload.proxy_note = `Assigned API key is invalid or revoked, please try again.`;
|
||||
|
@ -347,7 +350,7 @@ const handleUpstreamErrors: ProxyResHandlerWithBody = async (
|
|||
throw new HttpError(statusCode, errorPayload.error?.message);
|
||||
};
|
||||
|
||||
async function handleAnthropicBadRequestError(
|
||||
async function handleAnthropicAwsBadRequestError(
|
||||
req: Request,
|
||||
errorPayload: ProxiedErrorPayload
|
||||
) {
|
||||
|
@ -382,11 +385,13 @@ async function handleAnthropicBadRequestError(
|
|||
return;
|
||||
}
|
||||
|
||||
const isDisabled = error?.message?.match(/organization has been disabled/i);
|
||||
const isDisabled =
|
||||
error?.message?.match(/organization has been disabled/i) ||
|
||||
error?.message?.match(/^operation not allowed/i);
|
||||
if (isDisabled) {
|
||||
req.log.warn(
|
||||
{ key: req.key?.hash, message: error?.message },
|
||||
"Anthropic key has been disabled."
|
||||
"Anthropic/AWS key has been disabled."
|
||||
);
|
||||
keyPool.disable(req.key!, "revoked");
|
||||
errorPayload.proxy_note = `Assigned key has been disabled. (${error?.message})`;
|
||||
|
@ -512,7 +517,7 @@ async function handleOpenAIRateLimitError(
|
|||
// keyPool.markRateLimited(req.key!);
|
||||
// break;
|
||||
default:
|
||||
errorPayload.proxy_note = `This is likely a temporary error with OpenAI. Try again in a few seconds.`;
|
||||
errorPayload.proxy_note = `This is likely a temporary error with the API. Try again in a few seconds.`;
|
||||
break;
|
||||
}
|
||||
return errorPayload;
|
||||
|
|
Loading…
Reference in New Issue