Prettier errors and related improvements (#1387)
* improve get attempt payload logging * only log checkpoint readiness timeouts, don't crash the run * improve coordinator errors * add links export to core * remove unused deploy error utilities * update cli errors and use new links from core * log remaining failure reasons * also parse execute errors in deployed worker * add signal to unexpected exit messages * start displaying prettier internal errors * improve unexpected exit error parsing * better errors for crashes * fix unexpected error parsing for dev runs * changeset * parse graceful exit timeouts
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"trigger.dev": patch
|
||||
"@trigger.dev/core": patch
|
||||
---
|
||||
|
||||
Prettier and more specific errors with links to docs
|
||||
@@ -401,13 +401,16 @@ class TaskCoordinator {
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error("Error while waiting for checkpointable state", { error });
|
||||
logger.error("Error while waiting for checkpointable state", {
|
||||
error,
|
||||
runId: socket.data.runId,
|
||||
});
|
||||
|
||||
if (error instanceof CheckpointReadinessTimeoutError) {
|
||||
await crashRun({
|
||||
name: error.name,
|
||||
message: `Failed to become checkpointable in ${CHECKPOINTABLE_TIMEOUT_SECONDS}s for ${reason}`,
|
||||
});
|
||||
logger.error(
|
||||
`Failed to become checkpointable in ${CHECKPOINTABLE_TIMEOUT_SECONDS}s for ${reason}`,
|
||||
{ runId: socket.data.runId }
|
||||
);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -490,7 +493,7 @@ class TaskCoordinator {
|
||||
updateAttemptFriendlyId(executionAck.payload.execution.attempt.id);
|
||||
updateAttemptNumber(executionAck.payload.execution.attempt.number);
|
||||
} catch (error) {
|
||||
logger.error("Error", { error });
|
||||
logger.error("READY_FOR_EXECUTION error", { error, runId: socket.data.runId });
|
||||
|
||||
await crashRun({
|
||||
name: "ReadyForExecutionError",
|
||||
@@ -524,7 +527,10 @@ class TaskCoordinator {
|
||||
}
|
||||
|
||||
if (!lazyAttempt.success) {
|
||||
logger.error("failed to get lazy attempt payload", { runId: socket.data.runId });
|
||||
logger.error("failed to get lazy attempt payload", {
|
||||
runId: socket.data.runId,
|
||||
reason: lazyAttempt.reason,
|
||||
});
|
||||
|
||||
await crashRun({
|
||||
name: "ReadyForLazyAttemptError",
|
||||
@@ -546,7 +552,7 @@ class TaskCoordinator {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.error("Error", { error });
|
||||
logger.error("READY_FOR_LAZY_ATTEMPT error", { error, runId: socket.data.runId });
|
||||
|
||||
await crashRun({
|
||||
name: "ReadyForLazyAttemptError",
|
||||
@@ -1004,7 +1010,10 @@ class TaskCoordinator {
|
||||
});
|
||||
|
||||
if (!createAttempt?.success) {
|
||||
logger.debug("no ack while creating attempt", message);
|
||||
logger.debug("no ack while creating attempt", {
|
||||
runId: message.runId,
|
||||
reason: createAttempt?.reason,
|
||||
});
|
||||
callback({ success: false, reason: createAttempt?.reason });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ import { SimpleLogger } from "@trigger.dev/core/v3/apps";
|
||||
import { EXIT_CODE_ALREADY_HANDLED, EXIT_CODE_CHILD_NONZERO } from "@trigger.dev/core/v3/apps";
|
||||
import { setTimeout } from "timers/promises";
|
||||
import PQueue from "p-queue";
|
||||
import type { Prettify } from "@trigger.dev/core/v3";
|
||||
import { TaskRunErrorCodes, type Prettify, type TaskRunInternalError } from "@trigger.dev/core/v3";
|
||||
|
||||
type FailureDetails = Prettify<{
|
||||
exitCode: number;
|
||||
reason: string;
|
||||
logs: string;
|
||||
overrideCompletion: boolean;
|
||||
errorCode: TaskRunInternalError["code"];
|
||||
}>;
|
||||
|
||||
type IndexFailureHandler = (deploymentId: string, details: FailureDetails) => Promise<any>;
|
||||
@@ -160,18 +161,23 @@ export class TaskMonitor {
|
||||
let reason = rawReason || "Unknown error";
|
||||
let logs = rawLogs || "";
|
||||
let overrideCompletion = false;
|
||||
let errorCode: TaskRunInternalError["code"] = TaskRunErrorCodes.POD_UNKNOWN_ERROR;
|
||||
|
||||
switch (rawReason) {
|
||||
case "Error":
|
||||
reason = "Unknown error.";
|
||||
errorCode = TaskRunErrorCodes.POD_UNKNOWN_ERROR;
|
||||
break;
|
||||
case "Evicted":
|
||||
if (message.startsWith("Pod ephemeral local storage usage")) {
|
||||
reason = "Storage limit exceeded.";
|
||||
errorCode = TaskRunErrorCodes.DISK_SPACE_EXCEEDED;
|
||||
} else if (message) {
|
||||
reason = `Evicted: ${message}`;
|
||||
errorCode = TaskRunErrorCodes.POD_EVICTED;
|
||||
} else {
|
||||
reason = "Evicted for unknown reason.";
|
||||
errorCode = TaskRunErrorCodes.POD_EVICTED;
|
||||
}
|
||||
|
||||
if (logs.startsWith("failed to try resolving symlinks")) {
|
||||
@@ -183,6 +189,7 @@ export class TaskMonitor {
|
||||
reason = `${
|
||||
exitCode === EXIT_CODE_CHILD_NONZERO ? "Child process" : "Parent process"
|
||||
} ran out of memory! Try choosing a machine preset with more memory for this task.`;
|
||||
errorCode = TaskRunErrorCodes.TASK_PROCESS_OOM_KILLED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -193,6 +200,7 @@ export class TaskMonitor {
|
||||
reason,
|
||||
logs,
|
||||
overrideCompletion,
|
||||
errorCode,
|
||||
} satisfies FailureDetails;
|
||||
|
||||
const app = pod.metadata?.labels?.app;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { CheckIcon, ClockIcon, CloudArrowDownIcon, QueueListIcon } from "@heroicons/react/20/solid";
|
||||
import { Link } from "@remix-run/react";
|
||||
import { formatDuration, formatDurationMilliseconds, TaskRunError } from "@trigger.dev/core/v3";
|
||||
import {
|
||||
formatDuration,
|
||||
formatDurationMilliseconds,
|
||||
TaskRunError,
|
||||
taskRunErrorEnhancer,
|
||||
} from "@trigger.dev/core/v3";
|
||||
import { useEffect } from "react";
|
||||
import { useTypedFetcher } from "remix-typedjson";
|
||||
import { ExitIcon } from "~/assets/icons/ExitIcon";
|
||||
@@ -553,7 +558,9 @@ function RunTimeline({ run }: { run: RawRun }) {
|
||||
}
|
||||
|
||||
function RunError({ error }: { error: TaskRunError }) {
|
||||
switch (error.type) {
|
||||
const enhancedError = taskRunErrorEnhancer(error);
|
||||
|
||||
switch (enhancedError.type) {
|
||||
case "STRING_ERROR":
|
||||
case "CUSTOM_ERROR": {
|
||||
return (
|
||||
@@ -561,7 +568,7 @@ function RunError({ error }: { error: TaskRunError }) {
|
||||
<CodeBlock
|
||||
showCopyButton={false}
|
||||
showLineNumbers={false}
|
||||
code={error.raw}
|
||||
code={enhancedError.raw}
|
||||
maxLines={20}
|
||||
/>
|
||||
</div>
|
||||
@@ -569,16 +576,21 @@ function RunError({ error }: { error: TaskRunError }) {
|
||||
}
|
||||
case "BUILT_IN_ERROR":
|
||||
case "INTERNAL_ERROR": {
|
||||
const name = "name" in error ? error.name : error.code;
|
||||
const name = "name" in enhancedError ? enhancedError.name : enhancedError.code;
|
||||
return (
|
||||
<div className="flex flex-col gap-2 rounded-sm border border-rose-500/50 px-3 pb-3 pt-2">
|
||||
<Header3 className="text-rose-500">{name}</Header3>
|
||||
{error.message && <Callout variant="error">{error.message}</Callout>}
|
||||
{error.stackTrace && (
|
||||
{enhancedError.message && <Callout variant="error">{enhancedError.message}</Callout>}
|
||||
{enhancedError.link && (
|
||||
<Callout variant="docs" to={enhancedError.link.href}>
|
||||
{enhancedError.link.name}
|
||||
</Callout>
|
||||
)}
|
||||
{enhancedError.stackTrace && (
|
||||
<CodeBlock
|
||||
showCopyButton={false}
|
||||
showLineNumbers={false}
|
||||
code={error.stackTrace}
|
||||
code={enhancedError.stackTrace}
|
||||
maxLines={20}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
exceptionEventEnhancer,
|
||||
isExceptionSpanEvent,
|
||||
type ExceptionEventProperties,
|
||||
type SpanEvent as OtelSpanEvent,
|
||||
@@ -64,19 +65,26 @@ export function SpanEventError({
|
||||
spanEvent: OtelSpanEvent;
|
||||
exception: ExceptionEventProperties;
|
||||
}) {
|
||||
const enhancedException = exceptionEventEnhancer(exception);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2 rounded-sm border border-rose-500/50 px-3 pb-3 pt-2">
|
||||
<SpanEventHeader
|
||||
title={exception.type ?? "Error"}
|
||||
title={enhancedException.type ?? "Error"}
|
||||
time={spanEvent.time}
|
||||
titleClassName="text-rose-500"
|
||||
/>
|
||||
{exception.message && <Callout variant="error">{exception.message}</Callout>}
|
||||
{exception.stacktrace && (
|
||||
{enhancedException.message && <Callout variant="error">{enhancedException.message}</Callout>}
|
||||
{enhancedException.link && (
|
||||
<Callout variant="docs" to={enhancedException.link.href}>
|
||||
{enhancedException.link.name}
|
||||
</Callout>
|
||||
)}
|
||||
{enhancedException.stacktrace && (
|
||||
<CodeBlock
|
||||
showCopyButton={false}
|
||||
showLineNumbers={false}
|
||||
code={exception.stacktrace}
|
||||
code={enhancedException.stacktrace}
|
||||
maxLines={20}
|
||||
/>
|
||||
)}
|
||||
|
||||
+15
-7
@@ -6,6 +6,7 @@ import {
|
||||
formatDurationMilliseconds,
|
||||
nanosecondsToMilliseconds,
|
||||
TaskRunError,
|
||||
taskRunErrorEnhancer,
|
||||
} from "@trigger.dev/core/v3";
|
||||
import { ReactNode, useEffect } from "react";
|
||||
import { typedjson, useTypedFetcher } from "remix-typedjson";
|
||||
@@ -933,12 +934,14 @@ function RunTimelineLine({ title, state }: RunTimelineLineProps) {
|
||||
}
|
||||
|
||||
function RunError({ error }: { error: TaskRunError }) {
|
||||
switch (error.type) {
|
||||
const enhancedError = taskRunErrorEnhancer(error);
|
||||
|
||||
switch (enhancedError.type) {
|
||||
case "STRING_ERROR":
|
||||
return (
|
||||
<div className="flex flex-col gap-2 rounded-sm border border-rose-500/50 px-3 pb-3 pt-2">
|
||||
<Header3 className="text-rose-500">Error</Header3>
|
||||
<Callout variant="error">{error.raw}</Callout>
|
||||
<Callout variant="error">{enhancedError.raw}</Callout>
|
||||
</div>
|
||||
);
|
||||
case "CUSTOM_ERROR": {
|
||||
@@ -947,7 +950,7 @@ function RunError({ error }: { error: TaskRunError }) {
|
||||
<CodeBlock
|
||||
showCopyButton={false}
|
||||
showLineNumbers={false}
|
||||
code={error.raw}
|
||||
code={enhancedError.raw}
|
||||
maxLines={20}
|
||||
/>
|
||||
</div>
|
||||
@@ -955,16 +958,21 @@ function RunError({ error }: { error: TaskRunError }) {
|
||||
}
|
||||
case "BUILT_IN_ERROR":
|
||||
case "INTERNAL_ERROR": {
|
||||
const name = "name" in error ? error.name : error.code;
|
||||
const name = "name" in enhancedError ? enhancedError.name : enhancedError.code;
|
||||
return (
|
||||
<div className="flex flex-col gap-2 rounded-sm border border-rose-500/50 px-3 pb-3 pt-2">
|
||||
<Header3 className="text-rose-500">{name}</Header3>
|
||||
{error.message && <Callout variant="error">{error.message}</Callout>}
|
||||
{error.stackTrace && (
|
||||
{enhancedError.message && <Callout variant="error">{enhancedError.message}</Callout>}
|
||||
{enhancedError.link && (
|
||||
<Callout variant="docs" to={enhancedError.link.href}>
|
||||
{enhancedError.link.name}
|
||||
</Callout>
|
||||
)}
|
||||
{enhancedError.stackTrace && (
|
||||
<CodeBlock
|
||||
showCopyButton={false}
|
||||
showLineNumbers={false}
|
||||
code={error.stackTrace}
|
||||
code={enhancedError.stackTrace}
|
||||
maxLines={20}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -188,7 +188,7 @@ function createCoordinatorNamespace(io: Server) {
|
||||
const environment = await findEnvironmentById(message.envId);
|
||||
|
||||
if (!environment) {
|
||||
logger.error("Environment not found", { id: message.envId });
|
||||
logger.error("CREATE_TASK_RUN_ATTEMPT: Environment not found", message);
|
||||
return { success: false, reason: "Environment not found" };
|
||||
}
|
||||
|
||||
@@ -198,16 +198,14 @@ function createCoordinatorNamespace(io: Server) {
|
||||
const payload = await sharedQueueTasks.getExecutionPayloadFromAttempt(attempt.id, true);
|
||||
|
||||
if (!payload) {
|
||||
logger.error("Failed to retrieve payload after attempt creation", {
|
||||
id: message.envId,
|
||||
});
|
||||
logger.error("Failed to retrieve payload after attempt creation", message);
|
||||
return { success: false, reason: "Failed to retrieve payload" };
|
||||
}
|
||||
|
||||
return { success: true, executionPayload: payload };
|
||||
} catch (error) {
|
||||
logger.error("Error while creating attempt", {
|
||||
runId: message.runId,
|
||||
...message,
|
||||
error,
|
||||
});
|
||||
return { success: false };
|
||||
|
||||
@@ -1160,7 +1160,7 @@ class SharedQueueTasks {
|
||||
const environment = await findEnvironmentById(envId);
|
||||
|
||||
if (!environment) {
|
||||
logger.error("Environment not found", { id: envId });
|
||||
logger.error("getLazyAttemptPayload: Environment not found", { runId, envId });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1182,7 +1182,7 @@ class SharedQueueTasks {
|
||||
});
|
||||
|
||||
if (!run) {
|
||||
logger.error("Run not found", { id: runId, envId });
|
||||
logger.error("getLazyAttemptPayload: Run not found", { runId, envId });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { BaseService } from "./baseService.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
|
||||
import { CRASHABLE_ATTEMPT_STATUSES, isCrashableRunStatus } from "../taskStatus";
|
||||
import { sanitizeError } from "@trigger.dev/core/v3";
|
||||
import { sanitizeError, TaskRunInternalError } from "@trigger.dev/core/v3";
|
||||
import { FinalizeTaskRunService } from "./finalizeTaskRun.server";
|
||||
|
||||
export type CrashTaskRunServiceOptions = {
|
||||
@@ -15,6 +15,7 @@ export type CrashTaskRunServiceOptions = {
|
||||
crashAttempts?: boolean;
|
||||
crashedAt?: Date;
|
||||
overrideCompletion?: boolean;
|
||||
errorCode?: TaskRunInternalError["code"];
|
||||
};
|
||||
|
||||
export class CrashTaskRunService extends BaseService {
|
||||
@@ -26,6 +27,8 @@ export class CrashTaskRunService extends BaseService {
|
||||
...options,
|
||||
};
|
||||
|
||||
logger.debug("CrashTaskRunService.call", { runId, opts });
|
||||
|
||||
const taskRun = await this._prisma.taskRun.findFirst({
|
||||
where: {
|
||||
id: runId,
|
||||
@@ -71,7 +74,7 @@ export class CrashTaskRunService extends BaseService {
|
||||
attemptStatus: "FAILED",
|
||||
error: {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: "TASK_RUN_CRASHED",
|
||||
code: opts.errorCode ?? "TASK_RUN_CRASHED",
|
||||
message: opts.reason,
|
||||
stackTrace: opts.logs,
|
||||
},
|
||||
@@ -129,6 +132,7 @@ export class CrashTaskRunService extends BaseService {
|
||||
error: {
|
||||
reason: string;
|
||||
logs?: string;
|
||||
code?: TaskRunInternalError["code"];
|
||||
}
|
||||
) {
|
||||
return await this.traceWithEnv("failAttempt()", environment, async (span) => {
|
||||
@@ -146,7 +150,7 @@ export class CrashTaskRunService extends BaseService {
|
||||
completedAt: failedAt,
|
||||
error: sanitizeError({
|
||||
type: "INTERNAL_ERROR",
|
||||
code: "TASK_RUN_CRASHED",
|
||||
code: error.code ?? "TASK_RUN_CRASHED",
|
||||
message: error.reason,
|
||||
stackTrace: error.logs,
|
||||
}),
|
||||
|
||||
@@ -3,7 +3,7 @@ import { writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { chalkError, chalkWarning, cliLink } from "../utilities/cliOutput.js";
|
||||
import { createTempDir } from "../utilities/fileSystem.js";
|
||||
import { docs, getInTouch } from "../utilities/links.js";
|
||||
import { links } from "@trigger.dev/core/v3";
|
||||
|
||||
export type WarningsCheckReturn =
|
||||
| {
|
||||
@@ -46,27 +46,27 @@ export function checkLogsForErrors(logs: string) {
|
||||
const errors: LogParserOptions = [
|
||||
{
|
||||
regex: /Error: Provided --schema at (?<schema>.*) doesn't exist/,
|
||||
message: `Prisma generate failed to find the specified schema at "$schema".\nDid you include it in config.additionalFiles? ${cliLink(
|
||||
"Config docs",
|
||||
docs.config.prisma
|
||||
message: `Prisma generate failed to find the specified schema at "$schema".\nDid you configure the Prisma extension correctly? ${cliLink(
|
||||
"Extension docs",
|
||||
links.docs.config.prisma
|
||||
)}`,
|
||||
},
|
||||
{
|
||||
regex: /@prisma\/client did not initialize yet/,
|
||||
message: `Prisma client not initialized yet.\nDid you forget to add the postinstall script? ${cliLink(
|
||||
"Config docs",
|
||||
docs.config.prisma
|
||||
message: `Prisma client not initialized yet.\nDid you configure the Prisma extension? ${cliLink(
|
||||
"Extension docs",
|
||||
links.docs.config.prisma
|
||||
)}`,
|
||||
},
|
||||
{
|
||||
regex: /sh: 1: (?<packageOrBinary>.*): not found/,
|
||||
message: `$packageOrBinary not found\n\nIf it's a package: Include it in ${cliLink(
|
||||
"config.additionalPackages",
|
||||
docs.config.prisma
|
||||
)}\nIf it's a binary: Please ${cliLink(
|
||||
"get in touch",
|
||||
getInTouch
|
||||
)} and we'll see what we can do!`,
|
||||
message: `$packageOrBinary not found\n\nIf it's a package: Use the ${cliLink(
|
||||
"additionalPackages extension",
|
||||
links.docs.config.additionalPackages
|
||||
)}\nIf it's a binary: Check the other ${cliLink(
|
||||
"build extensions",
|
||||
links.docs.config.extensions
|
||||
)}`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -101,10 +101,10 @@ export function checkLogsForWarnings(logs: string): WarningsCheckReturn {
|
||||
const warnings: LogParserOptions = [
|
||||
{
|
||||
regex: /prisma:warn We could not find your Prisma schema/,
|
||||
message: `Prisma generate failed to find the default schema. Did you include it in config.additionalFiles? ${cliLink(
|
||||
"Config docs",
|
||||
docs.config.prisma
|
||||
)}\nCustom schema paths require a postinstall script like this: \`prisma generate --schema=./custom/path/to/schema.prisma\``,
|
||||
message: `Prisma generate failed to find the default schema. Did you configure the Prisma extension correctly? ${cliLink(
|
||||
"Extension docs",
|
||||
links.docs.config.prisma
|
||||
)}`,
|
||||
shouldFail: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
CreateBackgroundWorkerResponse,
|
||||
ServerBackgroundWorker,
|
||||
TaskRunBuiltInError,
|
||||
TaskRunErrorCodes,
|
||||
TaskRunExecution,
|
||||
TaskRunExecutionPayload,
|
||||
TaskRunExecutionResult,
|
||||
@@ -14,13 +13,7 @@ import {
|
||||
import { Evt } from "evt";
|
||||
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
CancelledProcessError,
|
||||
CleanupProcessError,
|
||||
SigKillTimeoutProcessError,
|
||||
UnexpectedExitError,
|
||||
getFriendlyErrorMessage,
|
||||
} from "@trigger.dev/core/v3/errors";
|
||||
import { SigKillTimeoutProcessError } from "@trigger.dev/core/v3/errors";
|
||||
import { TaskRunProcess, TaskRunProcessOptions } from "../executions/taskRunProcess.js";
|
||||
import { indexWorkerManifest } from "../indexing/indexWorkerManifest.js";
|
||||
import { prettyError } from "../utilities/cliOutput.js";
|
||||
@@ -490,7 +483,7 @@ export class BackgroundWorker {
|
||||
const error = result.error;
|
||||
|
||||
if (error.type === "BUILT_IN_ERROR") {
|
||||
const mappedError = await this.#correctError(error, payload.execution);
|
||||
const mappedError = await this.#correctError(error);
|
||||
|
||||
return {
|
||||
...result,
|
||||
@@ -500,61 +493,16 @@ export class BackgroundWorker {
|
||||
|
||||
return result;
|
||||
} catch (e) {
|
||||
if (e instanceof CancelledProcessError) {
|
||||
return {
|
||||
id: payload.execution.run.id,
|
||||
ok: false,
|
||||
retry: undefined,
|
||||
error: {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_RUN_CANCELLED,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (e instanceof CleanupProcessError) {
|
||||
return {
|
||||
id: payload.execution.run.id,
|
||||
ok: false,
|
||||
retry: undefined,
|
||||
error: {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_EXECUTION_ABORTED,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (e instanceof UnexpectedExitError) {
|
||||
return {
|
||||
id: payload.execution.run.id,
|
||||
ok: false,
|
||||
retry: undefined,
|
||||
error: {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_PROCESS_EXITED_WITH_NON_ZERO_CODE,
|
||||
message: getFriendlyErrorMessage(e.code, e.signal, e.stderr),
|
||||
stackTrace: e.stderr,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
id: payload.execution.run.id,
|
||||
ok: false,
|
||||
retry: undefined,
|
||||
error: {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_EXECUTION_FAILED,
|
||||
message: String(e),
|
||||
},
|
||||
error: TaskRunProcess.parseExecuteError(e),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async #correctError(
|
||||
error: TaskRunBuiltInError,
|
||||
execution: TaskRunExecution
|
||||
): Promise<TaskRunBuiltInError> {
|
||||
async #correctError(error: TaskRunBuiltInError): Promise<TaskRunBuiltInError> {
|
||||
return {
|
||||
...error,
|
||||
stackTrace: correctErrorStackTrace(error.stackTrace, this.params.cwd),
|
||||
|
||||
@@ -784,7 +784,22 @@ class ProdWorker {
|
||||
error,
|
||||
});
|
||||
|
||||
this.#failRun(message.lazyPayload.runId, error);
|
||||
try {
|
||||
await this._taskRunProcess.cancel();
|
||||
} catch (error) {
|
||||
logger.error("Failed to cancel task run process", { error });
|
||||
}
|
||||
|
||||
try {
|
||||
await this.#submitAttemptCompletion(execution, {
|
||||
id: execution.run.id,
|
||||
ok: false,
|
||||
retry: undefined,
|
||||
error: TaskRunProcess.parseExecuteError(error, !this.runningInKubernetes),
|
||||
});
|
||||
} catch (error) {
|
||||
this.#failRun(message.lazyPayload.runId, error);
|
||||
}
|
||||
}
|
||||
},
|
||||
REQUEST_ATTEMPT_CANCELLATION: async (message) => {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import {
|
||||
ExecutorToWorkerMessageCatalog,
|
||||
ServerBackgroundWorker,
|
||||
TaskRunErrorCodes,
|
||||
TaskRunExecution,
|
||||
TaskRunExecutionPayload,
|
||||
TaskRunExecutionResult,
|
||||
type TaskRunInternalError,
|
||||
WorkerManifest,
|
||||
WorkerToExecutorMessageCatalog,
|
||||
} from "@trigger.dev/core/v3";
|
||||
@@ -21,10 +23,10 @@ import { logger } from "../utilities/logger.js";
|
||||
import {
|
||||
CancelledProcessError,
|
||||
CleanupProcessError,
|
||||
internalErrorFromUnexpectedExit,
|
||||
GracefulExitTimeoutError,
|
||||
UnexpectedExitError,
|
||||
} from "@trigger.dev/core/v3/errors";
|
||||
import { env } from "std-env";
|
||||
|
||||
export type OnWaitForDurationMessage = InferSocketMessageSchema<
|
||||
typeof ExecutorToWorkerMessageCatalog,
|
||||
@@ -383,6 +385,39 @@ export class TaskRunProcess {
|
||||
get pid() {
|
||||
return this._childPid;
|
||||
}
|
||||
|
||||
static parseExecuteError(error: unknown, dockerMode = true): TaskRunInternalError {
|
||||
if (error instanceof CancelledProcessError) {
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_RUN_CANCELLED,
|
||||
};
|
||||
}
|
||||
|
||||
if (error instanceof CleanupProcessError) {
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_EXECUTION_ABORTED,
|
||||
};
|
||||
}
|
||||
|
||||
if (error instanceof UnexpectedExitError) {
|
||||
return internalErrorFromUnexpectedExit(error, dockerMode);
|
||||
}
|
||||
|
||||
if (error instanceof GracefulExitTimeoutError) {
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.GRACEFUL_EXIT_TIMEOUT,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_EXECUTION_FAILED,
|
||||
message: String(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function executorArgs(workerManifest: WorkerManifest): string[] {
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
import chalk from "chalk";
|
||||
import { relative } from "node:path";
|
||||
import {
|
||||
chalkError,
|
||||
chalkPurple,
|
||||
chalkGrey,
|
||||
chalkGreen,
|
||||
chalkWarning,
|
||||
cliLink,
|
||||
} from "./cliOutput.js";
|
||||
import { logger } from "./logger.js";
|
||||
import { z } from "zod";
|
||||
import { groupTaskMetadataIssuesByTask } from "@trigger.dev/core/v3";
|
||||
import { docs } from "./links.js";
|
||||
|
||||
export type ESMRequireError = {
|
||||
type: "esm-require-error";
|
||||
moduleName: string;
|
||||
};
|
||||
|
||||
export type BuildError = ESMRequireError | string;
|
||||
|
||||
function errorIsErrorLike(error: unknown): error is Error {
|
||||
return (
|
||||
error instanceof Error || (typeof error === "object" && error !== null && "message" in error)
|
||||
);
|
||||
}
|
||||
|
||||
export function parseBuildErrorStack(error: unknown): BuildError | undefined {
|
||||
if (typeof error === "string") {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (errorIsErrorLike(error)) {
|
||||
if (typeof error.stack === "string") {
|
||||
if (error.stack.includes("ERR_REQUIRE_ESM")) {
|
||||
const moduleName = getPackageNameFromEsmRequireError(error.stack);
|
||||
|
||||
if (moduleName) {
|
||||
return {
|
||||
type: "esm-require-error",
|
||||
moduleName,
|
||||
};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return error.message;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function getPackageNameFromEsmRequireError(stack: string): string | undefined {
|
||||
const pathRegex = /require\(\) of ES Module (.*) from/;
|
||||
const pathMatch = pathRegex.exec(stack);
|
||||
|
||||
if (!pathMatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filePath = pathMatch[1];
|
||||
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastPart = filePath.split("node_modules/").pop();
|
||||
|
||||
if (!lastPart) {
|
||||
return;
|
||||
}
|
||||
|
||||
// regular expression to match the package name
|
||||
const moduleRegex = /(@[^\/]+\/[^\/]+|[^\/]+)/;
|
||||
|
||||
const match = moduleRegex.exec(lastPart);
|
||||
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
|
||||
return match[1];
|
||||
}
|
||||
|
||||
export function logESMRequireError(parsedError: ESMRequireError) {
|
||||
logger.log(
|
||||
`\n${chalkError("X Error:")} The ${chalkPurple(
|
||||
parsedError.moduleName
|
||||
)} module is being required even though it's ESM only, and builds only support CommonJS. There are two ${chalk.underline(
|
||||
"possible"
|
||||
)} ways to fix this:`
|
||||
);
|
||||
logger.log(
|
||||
`\n${chalkGrey("○")} Dynamically import the module in your code: ${chalkGrey(
|
||||
`const myModule = await import("${parsedError.moduleName}");`
|
||||
)}`
|
||||
);
|
||||
|
||||
logger.log(
|
||||
`${chalkGrey("○")} ${chalk.underline("Or")} add ${chalkPurple(
|
||||
parsedError.moduleName
|
||||
)} to the ${chalkGreen("dependenciesToBundle")} array in your config file ${chalkGrey(
|
||||
"(you'll need to create one)"
|
||||
)}. This will bundle the module with your code.\n`
|
||||
);
|
||||
|
||||
logger.log(
|
||||
`${chalkGrey("○")} For more info see the ${cliLink("relevant docs", docs.config.esm)}.\n`
|
||||
);
|
||||
}
|
||||
|
||||
export type PackageNotFoundError = {
|
||||
type: "package-not-found-error";
|
||||
packageName: string;
|
||||
};
|
||||
|
||||
export type NoMatchingVersionError = {
|
||||
type: "no-matching-version-error";
|
||||
packageName: string;
|
||||
};
|
||||
|
||||
export type NpmInstallError = PackageNotFoundError | NoMatchingVersionError | string;
|
||||
|
||||
export function parseNpmInstallError(error: unknown): NpmInstallError {
|
||||
if (typeof error === "string") {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
if (typeof error.stack === "string") {
|
||||
const isPackageNotFoundError =
|
||||
error.stack.includes("ERR! 404 Not Found") &&
|
||||
error.stack.includes("is not in this registry");
|
||||
let packageName = null;
|
||||
|
||||
if (isPackageNotFoundError) {
|
||||
// Regular expression to match the package name
|
||||
const packageNameRegex = /'([^']+)' is not in this registry/;
|
||||
const match = packageNameRegex.exec(error.stack);
|
||||
if (match) {
|
||||
packageName = match[1] as string; // Capture the package name
|
||||
}
|
||||
}
|
||||
|
||||
if (packageName) {
|
||||
return {
|
||||
type: "package-not-found-error",
|
||||
packageName,
|
||||
};
|
||||
}
|
||||
|
||||
const noMatchingVersionRegex = /No matching version found for ([^\s]+)\s/;
|
||||
const noMatchingVersionMatch = noMatchingVersionRegex.exec(error.stack);
|
||||
if (noMatchingVersionMatch) {
|
||||
return {
|
||||
type: "no-matching-version-error",
|
||||
packageName: (noMatchingVersionMatch[1] as string).replace(/.$/, ""),
|
||||
};
|
||||
}
|
||||
|
||||
return error.message;
|
||||
} else {
|
||||
return error.message;
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
export function logTaskMetadataParseError(zodIssues: z.ZodIssue[], tasks: any) {
|
||||
logger.log(
|
||||
`\n${chalkError("X Error:")} Failed to start. The following ${
|
||||
zodIssues.length === 1 ? "task issue was" : "task issues were"
|
||||
} found:`
|
||||
);
|
||||
|
||||
const groupedIssues = groupTaskMetadataIssuesByTask(tasks, zodIssues);
|
||||
|
||||
for (const key in groupedIssues) {
|
||||
const taskWithIssues = groupedIssues[key];
|
||||
|
||||
if (!taskWithIssues) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.log(
|
||||
`\n ${chalkWarning("❯")} ${taskWithIssues.exportName} ${chalkGrey("in")} ${
|
||||
taskWithIssues.filePath
|
||||
}`
|
||||
);
|
||||
|
||||
for (const issue of taskWithIssues.issues) {
|
||||
if (issue.path) {
|
||||
logger.log(` ${chalkError("x")} ${issue.path} ${chalkGrey(issue.message)}`);
|
||||
} else {
|
||||
logger.log(` ${chalkError("x")} ${chalkGrey(issue.message)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
export const docs = {
|
||||
config: {
|
||||
home: "https://trigger.dev/docs/v3/trigger-config",
|
||||
esm: "https://trigger.dev/docs/v3/trigger-config#esm-only-packages",
|
||||
prisma: "https://trigger.dev/docs/v3/trigger-config#prisma-and-other-generators",
|
||||
additionalPackages: "https://trigger.dev/docs/v3/trigger-config#prisma-and-other-generators",
|
||||
},
|
||||
};
|
||||
|
||||
export const getInTouch = "https://trigger.dev/contact";
|
||||
+129
-35
@@ -1,8 +1,15 @@
|
||||
import { z } from "zod";
|
||||
import { DeploymentErrorData } from "./schemas/api.js";
|
||||
import { ImportTaskFileErrors, WorkerManifest } from "./schemas/build.js";
|
||||
import { SerializedError, TaskRunError } from "./schemas/common.js";
|
||||
import {
|
||||
SerializedError,
|
||||
TaskRunError,
|
||||
TaskRunErrorCodes,
|
||||
TaskRunInternalError,
|
||||
} from "./schemas/common.js";
|
||||
import { TaskMetadataFailedToParseData } from "./schemas/messages.js";
|
||||
import { links } from "./links.js";
|
||||
import { ExceptionEventProperties } from "./schemas/openTelemetry.js";
|
||||
|
||||
export class AbortTaskRunError extends Error {
|
||||
constructor(message: string) {
|
||||
@@ -68,27 +75,29 @@ export function createErrorTaskError(error: TaskRunError): any {
|
||||
}
|
||||
|
||||
export function createJsonErrorObject(error: TaskRunError): SerializedError {
|
||||
switch (error.type) {
|
||||
const enhancedError = taskRunErrorEnhancer(error);
|
||||
|
||||
switch (enhancedError.type) {
|
||||
case "BUILT_IN_ERROR": {
|
||||
return {
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
stackTrace: error.stackTrace,
|
||||
name: enhancedError.name,
|
||||
message: enhancedError.message,
|
||||
stackTrace: enhancedError.stackTrace,
|
||||
};
|
||||
}
|
||||
case "STRING_ERROR": {
|
||||
return {
|
||||
message: error.raw,
|
||||
message: enhancedError.raw,
|
||||
};
|
||||
}
|
||||
case "CUSTOM_ERROR": {
|
||||
return {
|
||||
message: error.raw,
|
||||
message: enhancedError.raw,
|
||||
};
|
||||
}
|
||||
case "INTERNAL_ERROR": {
|
||||
return {
|
||||
message: `trigger.dev internal error (${error.code})`,
|
||||
message: `trigger.dev internal error (${enhancedError.code})`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -265,7 +274,7 @@ export class UnexpectedExitError extends Error {
|
||||
public signal: NodeJS.Signals | null,
|
||||
public stderr: string | undefined
|
||||
) {
|
||||
super(`Unexpected exit with code ${code}`);
|
||||
super(`Unexpected exit with code ${code} after signal ${signal}`);
|
||||
|
||||
this.name = "UnexpectedExitError";
|
||||
}
|
||||
@@ -303,40 +312,125 @@ export class GracefulExitTimeoutError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export function getFriendlyErrorMessage(
|
||||
code: number,
|
||||
signal: NodeJS.Signals | null,
|
||||
stderr: string | undefined,
|
||||
const prettyInternalErrors: Partial<
|
||||
Record<TaskRunInternalError["code"], { message: string; link?: { name: string; href: string } }>
|
||||
> = {
|
||||
TASK_PROCESS_OOM_KILLED: {
|
||||
message:
|
||||
"Your task ran out of memory. Try increasing the machine specs. If this doesn't fix it there might be a memory leak.",
|
||||
link: {
|
||||
name: "Machines",
|
||||
href: links.docs.machines.home,
|
||||
},
|
||||
},
|
||||
TASK_PROCESS_MAYBE_OOM_KILLED: {
|
||||
message:
|
||||
"We think your task ran out of memory, but we can't be certain. If this keeps happening, try increasing the machine specs.",
|
||||
link: {
|
||||
name: "Machines",
|
||||
href: links.docs.machines.home,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
type EnhanceError<T extends TaskRunError | ExceptionEventProperties> = T & {
|
||||
link?: { name: string; href: string };
|
||||
};
|
||||
|
||||
export function taskRunErrorEnhancer(error: TaskRunError): EnhanceError<TaskRunError> {
|
||||
switch (error.type) {
|
||||
case "BUILT_IN_ERROR": {
|
||||
if (error.name === "UnexpectedExitError") {
|
||||
if (error.message.startsWith("Unexpected exit with code -1")) {
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_PROCESS_MAYBE_OOM_KILLED,
|
||||
...prettyInternalErrors.TASK_PROCESS_MAYBE_OOM_KILLED,
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "STRING_ERROR": {
|
||||
break;
|
||||
}
|
||||
case "CUSTOM_ERROR": {
|
||||
break;
|
||||
}
|
||||
case "INTERNAL_ERROR": {
|
||||
if (error.code === TaskRunErrorCodes.TASK_PROCESS_EXITED_WITH_NON_ZERO_CODE) {
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_PROCESS_MAYBE_OOM_KILLED,
|
||||
...prettyInternalErrors.TASK_PROCESS_MAYBE_OOM_KILLED,
|
||||
};
|
||||
}
|
||||
|
||||
const prettyError = prettyInternalErrors[error.code];
|
||||
|
||||
if (prettyError) {
|
||||
return {
|
||||
...error,
|
||||
...prettyError,
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
export function exceptionEventEnhancer(
|
||||
exception: ExceptionEventProperties
|
||||
): EnhanceError<ExceptionEventProperties> {
|
||||
switch (exception.type) {
|
||||
case "UnexpectedExitError": {
|
||||
if (exception.message?.startsWith("Unexpected exit with code -1")) {
|
||||
return {
|
||||
...exception,
|
||||
...prettyInternalErrors.TASK_PROCESS_MAYBE_OOM_KILLED,
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return exception;
|
||||
}
|
||||
|
||||
export function internalErrorFromUnexpectedExit(
|
||||
error: UnexpectedExitError,
|
||||
dockerMode = true
|
||||
) {
|
||||
const message = (text: string) => {
|
||||
if (signal) {
|
||||
return `[${signal}] ${text}`;
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
if (code === 137) {
|
||||
): TaskRunInternalError {
|
||||
if (error.code === 137) {
|
||||
if (dockerMode) {
|
||||
return message(
|
||||
"Process ran out of memory! Try choosing a machine preset with more memory for this task."
|
||||
);
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_PROCESS_OOM_KILLED,
|
||||
};
|
||||
} else {
|
||||
// Note: containerState reason and message should be checked to clarify the error
|
||||
return message(
|
||||
"Process most likely ran out of memory, but we can't be certain. Try choosing a machine preset with more memory for this task."
|
||||
);
|
||||
// Note: containerState reason and message could be checked to clarify the error, maybe the task monitor should be allowed to override these
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_PROCESS_MAYBE_OOM_KILLED,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (stderr?.includes("OOMErrorHandler")) {
|
||||
return message(
|
||||
"Process ran out of memory! Try choosing a machine preset with more memory for this task."
|
||||
);
|
||||
if (error.stderr?.includes("OOMErrorHandler")) {
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_PROCESS_OOM_KILLED,
|
||||
};
|
||||
}
|
||||
|
||||
return message(`Process exited with code ${code}.`);
|
||||
return {
|
||||
type: "INTERNAL_ERROR",
|
||||
code: TaskRunErrorCodes.TASK_PROCESS_EXITED_WITH_NON_ZERO_CODE,
|
||||
message: `Process exited with code ${error.code} after signal ${error.signal}.`,
|
||||
};
|
||||
}
|
||||
|
||||
export function serializeIndexingError(error: unknown, stderr?: string): DeploymentErrorData {
|
||||
|
||||
@@ -17,6 +17,7 @@ export * from "./schemas/index.js";
|
||||
export { SemanticInternalAttributes } from "./semanticInternalAttributes.js";
|
||||
export * from "./task-catalog-api.js";
|
||||
export * from "./types/index.js";
|
||||
export { links } from "./links.js";
|
||||
export {
|
||||
formatDuration,
|
||||
formatDurationInDays,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
export const links = {
|
||||
docs: {
|
||||
config: {
|
||||
home: "https://trigger.dev/docs/config/config-file",
|
||||
additionalPackages: "https://trigger.dev/docs/config/config-file#additionalpackages",
|
||||
extensions: "https://trigger.dev/docs/config/config-file#extensions",
|
||||
prisma: "https://trigger.dev/docs/config/config-file#prisma",
|
||||
},
|
||||
machines: {
|
||||
home: "https://trigger.dev/docs/v3/machines",
|
||||
},
|
||||
},
|
||||
site: {
|
||||
home: "https://trigger.dev",
|
||||
contact: "https://trigger.dev/contact",
|
||||
},
|
||||
};
|
||||
@@ -87,12 +87,17 @@ export const TaskRunErrorCodes = {
|
||||
TASK_EXECUTION_ABORTED: "TASK_EXECUTION_ABORTED",
|
||||
TASK_PROCESS_EXITED_WITH_NON_ZERO_CODE: "TASK_PROCESS_EXITED_WITH_NON_ZERO_CODE",
|
||||
TASK_PROCESS_SIGKILL_TIMEOUT: "TASK_PROCESS_SIGKILL_TIMEOUT",
|
||||
TASK_PROCESS_OOM_KILLED: "TASK_PROCESS_OOM_KILLED",
|
||||
TASK_PROCESS_MAYBE_OOM_KILLED: "TASK_PROCESS_MAYBE_OOM_KILLED",
|
||||
TASK_RUN_CANCELLED: "TASK_RUN_CANCELLED",
|
||||
TASK_OUTPUT_ERROR: "TASK_OUTPUT_ERROR",
|
||||
HANDLE_ERROR_ERROR: "HANDLE_ERROR_ERROR",
|
||||
GRACEFUL_EXIT_TIMEOUT: "GRACEFUL_EXIT_TIMEOUT",
|
||||
TASK_RUN_CRASHED: "TASK_RUN_CRASHED",
|
||||
MAX_DURATION_EXCEEDED: "MAX_DURATION_EXCEEDED",
|
||||
DISK_SPACE_EXCEEDED: "DISK_SPACE_EXCEEDED",
|
||||
POD_EVICTED: "POD_EVICTED",
|
||||
POD_UNKNOWN_ERROR: "POD_UNKNOWN_ERROR",
|
||||
} as const;
|
||||
|
||||
export const TaskRunInternalError = z.object({
|
||||
@@ -107,6 +112,8 @@ export const TaskRunInternalError = z.object({
|
||||
"TASK_EXECUTION_ABORTED",
|
||||
"TASK_PROCESS_EXITED_WITH_NON_ZERO_CODE",
|
||||
"TASK_PROCESS_SIGKILL_TIMEOUT",
|
||||
"TASK_PROCESS_OOM_KILLED",
|
||||
"TASK_PROCESS_MAYBE_OOM_KILLED",
|
||||
"TASK_RUN_CANCELLED",
|
||||
"TASK_OUTPUT_ERROR",
|
||||
"HANDLE_ERROR_ERROR",
|
||||
@@ -114,6 +121,9 @@ export const TaskRunInternalError = z.object({
|
||||
"TASK_RUN_HEARTBEAT_TIMEOUT",
|
||||
"TASK_RUN_CRASHED",
|
||||
"MAX_DURATION_EXCEEDED",
|
||||
"DISK_SPACE_EXCEEDED",
|
||||
"POD_EVICTED",
|
||||
"POD_UNKNOWN_ERROR",
|
||||
]),
|
||||
message: z.string().optional(),
|
||||
stackTrace: z.string().optional(),
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
TaskRunExecution,
|
||||
TaskRunExecutionResult,
|
||||
TaskRunFailedExecutionResult,
|
||||
TaskRunInternalError,
|
||||
} from "./common.js";
|
||||
import { TaskResource } from "./resources.js";
|
||||
import {
|
||||
@@ -252,6 +253,7 @@ export const ProviderToPlatformMessages = {
|
||||
message: z.string().optional(),
|
||||
logs: z.string().optional(),
|
||||
overrideCompletion: z.boolean().optional(),
|
||||
errorCode: TaskRunInternalError.shape.code.optional(),
|
||||
}),
|
||||
},
|
||||
INDEXING_FAILED: {
|
||||
|
||||
Reference in New Issue
Block a user