Skip to content

Fix error detection again BEN-1078 #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 209 additions & 23 deletions lib/e2b.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { benchifyFileSchema } from './schemas';
import { z } from 'zod';
import { fetchAllSandboxFiles } from './file-filter';
import { applyTransformations } from './sandbox-helpers';
import { detectCodeErrors, parseTypeScriptErrors } from './error-detection';

const E2B_API_KEY = process.env.E2B_API_KEY;

Expand Down Expand Up @@ -89,36 +88,225 @@ export async function createSandbox({ files }: { files: z.infer<typeof benchifyF
// Start dev server in background
const devServerResult = await sandbox.commands.run('cd /app && npm run dev', { background: true });

console.log('Dev server command executed');
console.log('Dev server exit code:', devServerResult.exitCode);
console.log('Dev server stderr:', devServerResult.stderr || 'No stderr');
console.log('Dev server stdout:', devServerResult.stdout || 'No stdout');
console.log('=== DEV SERVER INITIAL RESULT ===');
console.log('Exit code:', devServerResult.exitCode);
console.log('Stderr length:', devServerResult.stderr?.length || 0);
console.log('Stdout length:', devServerResult.stdout?.length || 0);
console.log('Stderr content:', devServerResult.stderr || 'No stderr');
console.log('Stdout content:', devServerResult.stdout || 'No stdout');

// Give it a moment to start and potentially fail
console.log('Waiting 3 seconds for dev server to start...');
await new Promise(resolve => setTimeout(resolve, 3000));
console.log('Waiting 5 seconds for dev server to start...');
await new Promise(resolve => setTimeout(resolve, 5000));

// Check the initial output for immediate errors
if (devServerResult.stderr || devServerResult.stdout) {
const allOutput = (devServerResult.stderr || '') + '\n' + (devServerResult.stdout || '');

// Use the error detection module
const errorResult = detectCodeErrors(allOutput);
// Check if the dev server is actually running by trying to access it
console.log('=== CHECKING IF DEV SERVER IS ACTUALLY RUNNING ===');
try {
const healthCheck = await sandbox.commands.run('curl -s -o /dev/null -w "%{http_code}" http://localhost:5173', { timeoutMs: 5000 });
console.log('Health check result:', healthCheck);
console.log('HTTP status code:', healthCheck.stdout);

if (errorResult.hasErrors) {
console.log('🔴 CODE ERRORS DETECTED!');
buildErrors.push(...errorResult.errors);
} else if (errorResult.isInfrastructureOnly) {
console.log('⚠️ Only infrastructure errors detected (ignoring)');
if (healthCheck.stdout === '200') {
console.log('✅ Dev server is running successfully despite permission errors!');
} else {
console.log('✅ No errors detected');
console.log('❌ Dev server is not responding properly');
}
} else {
console.log('⚠️ No stderr or stdout from dev server command');
} catch (healthError) {
console.log('Health check failed:', healthError);
}

// Check what processes are running
console.log('=== CHECKING RUNNING PROCESSES ===');
try {
const processCheck = await sandbox.commands.run('ps aux | grep -E "(vite|node)" | grep -v grep');
console.log('Running processes:', processCheck.stdout);
} catch (processError) {
console.log('Process check failed:', processError);
}

// Check if there are any recent logs
console.log('=== CHECKING FOR RECENT COMMAND OUTPUT ===');
try {
const recentLogs = await sandbox.commands.run('cd /app && timeout 2s npm run dev 2>&1 || true');
console.log('Recent dev server attempt:', recentLogs.stdout);
console.log('Recent dev server stderr:', recentLogs.stderr);
} catch (logError) {
console.log('Recent logs check failed:', logError);
}

// Simplified error detection: if there's stderr output or non-zero exit, it's likely an error
const hasStderr = devServerResult.stderr && devServerResult.stderr.trim().length > 0;
const hasErrorInStdout = devServerResult.stdout && (
devServerResult.stdout.includes('error') ||
devServerResult.stdout.includes('Error') ||
devServerResult.stdout.includes('failed') ||
devServerResult.stdout.includes('Failed')
);

// Check if the errors are just permission issues that don't prevent the server from working
const isPermissionError = devServerResult.stderr &&
devServerResult.stderr.includes('EACCES: permission denied') &&
devServerResult.stderr.includes('/app/node_modules/.vite-temp/');

// Check for actual compilation/build errors in the recent logs
let hasCompilationError = false;
let compilationErrorOutput = '';

console.log('=== COMPILATION ERROR CHECK ===');

// Try multiple approaches to detect compilation errors
try {
// Approach 1: Try to build the project
console.log('Trying npm run build...');
const buildCheck = await sandbox.commands.run('cd /app && timeout 10s npm run build 2>&1 || true');
console.log('Build check output:', buildCheck.stdout);
console.log('Build check stderr:', buildCheck.stderr);

if (buildCheck.stdout && (
buildCheck.stdout.includes('Unterminated string constant') ||
buildCheck.stdout.includes('SyntaxError') ||
buildCheck.stdout.includes('Unexpected token') ||
buildCheck.stdout.includes('Parse error') ||
buildCheck.stdout.includes('[plugin:vite:') ||
buildCheck.stdout.includes('Transform failed') ||
buildCheck.stdout.includes('Build failed')
)) {
hasCompilationError = true;
compilationErrorOutput = buildCheck.stdout;
console.log('✅ Found compilation error in build output');
}
} catch (buildError) {
console.log('Build check failed:', buildError);
}

// Approach 2: Try to check TypeScript compilation
if (!hasCompilationError) {
try {
console.log('Trying tsc --noEmit...');
const tscCheck = await sandbox.commands.run('cd /app && timeout 10s npx tsc --noEmit 2>&1 || true');
console.log('TypeScript check output:', tscCheck.stdout);
console.log('TypeScript check stderr:', tscCheck.stderr);

if (tscCheck.stdout && (
tscCheck.stdout.includes('error TS') ||
tscCheck.stdout.includes('Unterminated string constant') ||
tscCheck.stdout.includes('SyntaxError')
)) {
hasCompilationError = true;
compilationErrorOutput = tscCheck.stdout;
console.log('✅ Found compilation error in TypeScript check');
}
} catch (tscError) {
console.log('TypeScript check failed:', tscError);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Handle Non-Critical Permission Errors

The system should recognize but not consider E2B sandbox permission errors critical unless they prevent function.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[[{"files":[{"path":"P... view full input 400 100.0%

view all inputs
The property test has failed with an AssertionError. The test expected the result of createSandbox function to have no errors, but it did have errors. The error was not a critical permission error, but rather a compilation error or a dev server error. The error output was not provided in the trace, but the test suggests that it might be related to a compilation issue or a error in the dev server output.

Stack Trace
Error: expect(received).toBe(expected)

Expected: true
Received: false

    at toBe (unknown)
    at <anonymous> (/app/repo/lib/pver_9611c942-f8a0-4af7-8f8c-5772d008ffe5.test.ts:77:25)
    at <anonymous> (/app/repo/lib/pver_9611c942-f8a0-4af7-8f8c-5772d008ffe5.test.ts:52:16)
    at <anonymous> (/app/configuration/fc.setup.ts:156:17)
    at <anonymous> (/app/configuration/fc.setup.ts:143:38)
    at <anonymous> (/app/node_modules/fast-check/lib/esm/check/property/AsyncProperty.generic.js:46:39)
    at run (/app/node_modules/fast-check/lib/esm/check/property/AsyncProperty.generic.js:41:15)
    at run (/app/node_modules/fast-check/lib/esm/check/property/SkipAfterProperty.js:50:57)
    at <anonymous> (/app/node_modules/fast-check/lib/esm/check/runner/Runner.js:33:36)
    at processTicksAndRejections (native:7:39)
Unit Tests
// Unit Test for "Handle Non-Critical Permission Errors": The system should recognize but not consider E2B sandbox permission errors critical unless they prevent function.
async function benchify_s(s) {
    return s.replace(/[^a-zA-Z0-9]/g, 'a');
}

it('benchify_s_exec_test_failing_0', () => {
  const args = superjson.parse(
    '{"json":[[{"files":[{"path":"P","content":"8"},{"path":"|[8i","content":"q4YaL"},{"path":"SLZ7vCZIvd","content":"aM"},{"path":"iSP","content":"aeQa9gaa8"},{"path":"y\\"%","content":"9"},{"path":"VD(","content":"a3auma"},{"path":"\',M(AN","content":"bfEaaSNo"},{"path":" &s~","content":"a"}]}]]}',
  );

  benchify_s(...args);
});

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Package Installation with New Dependencies

If the package.json file is detected, new dependencies should be installed, with critical errors captured in buildErrors.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[[{"files":[{"path":"a... view full input 200 100.0%

view all inputs
The property test has PASSED. The test checks that when a package.json file is detected, new dependencies are installed, and critical errors are captured in buildErrors. The input files provided contained multiple package.json files with varying content, and the createSandbox function successfully installed dependencies and handled any errors that occurred during the process. The test did not encounter any critical errors, and the buildErrors array remained empty.

Unit Tests
// Unit Test for "Package Installation with New Dependencies": If the `package.json` file is detected, new dependencies should be installed, with critical errors captured in `buildErrors`.
function benchify_s(s) {
    return s.replace(/[^a-zA-Z0-9]/g, 'a');
}

it('benchify_s_exec_test_passing_0', () => {
  const args = superjson.parse(
    '{"json":[[{"files":[{"path":"anotherFile.js","content":"aaOapro"},{"path":"anotherFile.js","content":"ataaoLuc"},{"path":"package.json","content":"aciun"},{"path":"anotherFile.js","content":"tauoaz"},{"path":"anotherFile.js","content":"callotot"},{"path":"anotherFile.js","content":"1"},{"path":"anotherFile.js","content":"alba"},{"path":"anotherFile.js","content":"aaOaeYxa4J"},{"path":"package.json","content":"fvaXa"},{"path":"anotherFile.js","content":"8"},{"path":"anotherFile.js","content":"RaDa"},{"path":"package.json","content":"ana"}]}]]}',
  );

  benchify_s(...args);
});

}
}

// Approach 3: Try to parse files directly with Babel/ESLint
if (!hasCompilationError) {
try {
console.log('Trying to parse main files...');
const parseCheck = await sandbox.commands.run('cd /app && timeout 10s npx babel src/App.tsx --presets=@babel/preset-typescript 2>&1 || true');
console.log('Parse check output:', parseCheck.stdout);
console.log('Parse check stderr:', parseCheck.stderr);

if (parseCheck.stderr && (
parseCheck.stderr.includes('Unterminated string constant') ||
parseCheck.stderr.includes('SyntaxError') ||
parseCheck.stderr.includes('Unexpected token')
)) {
hasCompilationError = true;
compilationErrorOutput = parseCheck.stderr;
console.log('✅ Found compilation error in parse check');
}
} catch (parseError) {
console.log('Parse check failed:', parseError);
}
}

// Approach 4: Check if the dev server is actually serving errors
if (!hasCompilationError) {
try {
console.log('Checking dev server response for errors...');
const responseCheck = await sandbox.commands.run('cd /app && timeout 5s curl -s http://localhost:5173 2>&1 || true');
console.log('Response check output:', responseCheck.stdout);

if (responseCheck.stdout && (
responseCheck.stdout.includes('SyntaxError') ||
responseCheck.stdout.includes('Unterminated string') ||
responseCheck.stdout.includes('Parse error') ||
responseCheck.stdout.includes('Transform failed')
)) {
hasCompilationError = true;
compilationErrorOutput = responseCheck.stdout;
console.log('✅ Found compilation error in dev server response');
}
} catch (responseError) {
console.log('Response check failed:', responseError);
}
}

// Approach 5: Check Vite logs more thoroughly
if (!hasCompilationError) {
try {
console.log('Checking for Vite process logs...');
const viteLogsCheck = await sandbox.commands.run('cd /app && ps aux | grep vite');
console.log('Vite processes:', viteLogsCheck.stdout);

// Try to get logs from the running Vite process
const viteLogCheck = await sandbox.commands.run('cd /app && timeout 3s strace -p $(pgrep -f "vite --host") 2>&1 | head -20 || true');
console.log('Vite process trace:', viteLogCheck.stdout);
} catch (viteError) {
console.log('Vite log check failed:', viteError);
}
}

console.log('=== COMPILATION ERROR CHECK SUMMARY ===');
console.log('Has compilation error:', hasCompilationError);
console.log('Compilation error output length:', compilationErrorOutput.length);
if (compilationErrorOutput) {
console.log('Compilation error preview:', compilationErrorOutput.substring(0, 500));
}

console.log('Dev server started, output checked');
console.log('Total build errors found:', buildErrors.length);

console.log('=== ERROR ANALYSIS ===');
console.log('Has stderr:', hasStderr);
console.log('Has error in stdout:', hasErrorInStdout);
console.log('Is permission error:', isPermissionError);
console.log('Has compilation error:', hasCompilationError);

if (hasCompilationError || ((hasStderr || hasErrorInStdout) && !isPermissionError)) {
console.log('🔴 REAL ERRORS DETECTED IN DEV SERVER OUTPUT');

// Get the actual error output for display
let errorOutput = '';

if (hasCompilationError) {
// Use the compilation error output we found
errorOutput = compilationErrorOutput;
console.log('Using compilation error output for display');
} else {
// Use the original stderr/stdout
errorOutput = [devServerResult.stderr, devServerResult.stdout]
.filter(Boolean)
.join('\n')
.trim();
console.log('Using dev server stderr/stdout for display');
}

if (errorOutput) {
console.log('Adding build error with message length:', errorOutput.length);
buildErrors.push({
type: 'build',
message: errorOutput
});
}
} else if (isPermissionError) {
console.log('⚠️ Permission errors detected but likely non-critical (E2B sandbox issue)');
} else {
console.log('✅ No errors detected in dev server output');
}
} catch (error) {
console.error('Dev server check failed:', error);
buildErrors.push({
Expand All @@ -142,8 +330,6 @@ export async function createSandbox({ files }: { files: z.infer<typeof benchifyF
};
}



function extractNewPackages(packageJsonContent: string): string[] {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Function handles JSON parsing errors gracefully

The function must handle any errors that occur during JSON parsing by catching them, logging an appropriate error message, and returning an empty array.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[["fE"]]}')... view full input 200 100.0%

view all inputs
The test has passed successfully. The function extractNewPackages correctly handled the invalid JSON string "{\"json\":[[\"fE\"]]}" by catching the parsing error, logging an error message, and returning an empty array as expected.

Unit Tests
// Unit Test for "Function handles JSON parsing errors gracefully": The function must handle any errors that occur during JSON parsing by catching them, logging an appropriate error message, and returning an empty array.
function benchify_s(s) {
    return s.replace(/[^a-zA-Z0-9]/g, 'a');
}

it('benchify_s_exec_test_passing_0', () => {
  const args = superjson.parse('{"json":[["fE"]]}');

  benchify_s(...args);
});

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Function correctly identifies and formats new dependencies from package.json

The function should take a JSON string that represents a package.json file, parse it, and identify any dependencies that are not part of a predefined set of base packages. It returns an array of strings, each in the format 'package@version', for these new packages.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[[{"aWaa":",^z","ga5an... view full input 500 100.0%

view all inputs
The test has passed, which means the extractNewPackages function is working correctly. It successfully identified new packages in the provided package.json content that are not part of the predefined set of base packages and returned them in the correct 'package@version' format.

Unit Tests
// Unit Test for "Function correctly identifies and formats new dependencies from package.json": The function should take a JSON string that represents a package.json file, parse it, and identify any dependencies that are not part of a predefined set of base packages. It returns an array of strings, each in the format 'package@version', for these new packages.
function benchify_s(s) {
    return s.replace(/[^a-zA-Z0-9]/g, 'a');
}

it('benchify_s_exec_test_passing_0', () => {
  const args = superjson.parse(
    '{"json":[[{"aWaa":",^z","ga5ansoalF":"jWgMFOygk"}]]}',
  );

  benchify_s(...args);
});

try {
const packageJson = JSON.parse(packageJsonContent);
Expand Down
3 changes: 2 additions & 1 deletion lib/error-detection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function detectCodeErrors(output: string): ErrorDetectionResult {
const hasSyntaxError = output.includes('SyntaxError');
const hasUnexpectedToken = output.includes('Unexpected token');
const hasParseError = output.includes('Parse error');
const hasUnterminatedString = output.includes('Unterminated string');
const hasUnterminatedString = output.includes('Unterminated string') || output.includes('Unterminated string constant');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Code Error Detection

The function should detect code errors based on the presence of specific error indicators (e.g., 'SyntaxError', 'Unexpected token', etc.) and return an ErrorDetectionResult with hasErrors set to true, a list of errors, and isInfrastructureOnly set to false.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[["isProto"]]}')... view full input 200 100.0%

view all inputs
The test has passed, which means the detectCodeErrors function correctly identified code errors in the given output string. The output "{\"json\":[[\"isProto\"]]}" contains a code error, and the function returned an ErrorDetectionResult with hasErrors set to true, a list of errors, and isInfrastructureOnly set to false. The function correctly distinguished between code errors and infrastructure errors, meeting the expected behavior described in the property description.

Unit Tests
// Unit Test for "Code Error Detection": The function should detect code errors based on the presence of specific error indicators (e.g., 'SyntaxError', 'Unexpected token', etc.) and return an ErrorDetectionResult with hasErrors set to true, a list of errors, and isInfrastructureOnly set to false.
function benchify_output(output) {
    const codeErrors = ['SyntaxError', 'Unexpected token', 'Parse error', 'Unterminated string'];
    const infraErrors = ['EACCES: permission denied', 'failed to load config from /app/vite.config.ts', 'error when starting dev server'];
    const errorOutput = codeErrors.some((err) => output.includes(err)) && infraErrors.every((err) => !output.includes(err));
    const result = detectCodeErrors(output);
    if (errorOutput) {
        expect(result.hasErrors).toBe(true);
        expect(result.isInfrastructureOnly).toBe(false);
        expect(result.errors.length).toBeGreaterThan(0);
    }
}

it('benchify_output_exec_test_passing_0', () => {
  const args = superjson.parse('{"json":[["isProto"]]}');

  benchify_output(...args);
});

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No Error Detected Behavior

If no relevant errors (neither code errors nor known infrastructure errors) are detected in the output, the function should return an ErrorDetectionResult with hasErrors set to false, an empty list for errors, and isInfrastructureOnly set to false.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[["aa"]]}')... view full input 200 100.0%

view all inputs
The test has passed, indicating that the detectCodeErrors function correctly handled the provided output and did not detect any errors. The output {"json":[["aa"]]} was cleaned and checked for specific error keywords, resulting in no errors being reported and hasErrors set to false.

Unit Tests
// Unit Test for "No Error Detected Behavior": If no relevant errors (neither code errors nor known infrastructure errors) are detected in the output, the function should return an ErrorDetectionResult with hasErrors set to false, an empty list for errors, and isInfrastructureOnly set to false.
function benchify_s(s) {
    return s.replace(/[^a-zA-Z0-9]/g, 'a');
}

it('benchify_s_exec_test_passing_0', () => {
  const args = superjson.parse('{"json":[["aa"]]}');

  benchify_s(...args);
});

const hasModuleError = output.includes('Cannot resolve module') || output.includes('Module not found');
const hasImportError = output.includes('Cannot resolve import');

Expand Down Expand Up @@ -122,6 +122,7 @@ function parseErrorsFromOutput(output: string): BuildError[] {
line.includes('Unexpected token') ||
line.includes('Parse error') ||
line.includes('Unterminated string') ||
line.includes('Unterminated string constant') ||
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Excludes Mixed Code and Infrastructure Errors

The function should exclude any errors from the output that contain both code and infrastructure error identifiers, ensuring no mixed errors are erroneously included.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[["aaaMia8","Untermina... view full input 200 100.0%

view all inputs
The test has passed successfully. The function parseErrorsFromOutput correctly identified and excluded the mixed error containing both code and infrastructure error identifiers, as expected. The input string "{\"json\":[[\"aaaMia8\",\"Unterminated string constant\\\\n/app/node_modules/.vite-temp/\"]]}" was processed correctly, and no errors were included in the output.

Unit Tests
// Unit Test for "Excludes Mixed Code and Infrastructure Errors": The function should exclude any errors from the output that contain both code and infrastructure error identifiers, ensuring no mixed errors are erroneously included.
function benchify_s(s) {
    return s.replace(/[^a-zA-Z0-9]/g, 'a');
}

it('benchify_s_exec_test_passing_0', () => {
  const args = superjson.parse(
    '{"json":[["aaaMia8","Unterminated string constant\\\\n/app/node_modules/.vite-temp/"]]}',
  );

  benchify_s(...args);
});

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Returns Properly Structured BuildError Objects

The function should return an array where each element is a correctly structured BuildError object, with 'type' and 'message' fields correct and populated.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[["xAwqa2aNae"]]}')... view full input 200 100.0%

view all inputs
The test has passed, indicating that the parseErrorsFromOutput function is correctly returning an array of BuildError objects with 'type' and 'message' fields when given a string input. The test input was a string containing a JSON object with a specific structure, and the function successfully parsed and returned an array of errors with the correct information.

Unit Tests
// Unit Test for "Returns Properly Structured BuildError Objects": The function should return an array where each element is a correctly structured `BuildError` object, with 'type' and 'message' fields correct and populated.
function benchify_s(s) {
    return s.replace(/[^a-zA-Z0-9]/g, 'a');
}

it('benchify_s_exec_test_passing_0', () => {
  const args = superjson.parse('{"json":[["xAwqa2aNae"]]}');

  benchify_s(...args);
});

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Verifies Idempotency of Function

Reflining the function's claim of idempotency: feeding its output as the input should return the same results confirms its idempotent nature, as it processes valid code error lines consistently.

Outcome Example Input # Inputs % of Total
superjson.parse('{"json":[["aaO"]]}')... view full input 200 100.0%

view all inputs
Since the test has passed, there's no error to report. The provided property-based test successfully confirmed the idempotent nature of the parseErrorsFromOutput function, which means that feeding its output as the input returns the same results, processing valid code error lines consistently. The test input ["{\"json\":[[\"aaO\"]]}"] was successfully parsed and re-parsed without any issues.

Unit Tests
// Unit Test for "Verifies Idempotency of Function": Reflining the function's claim of idempotency: feeding its output as the input should return the same results confirms its idempotent nature, as it processes valid code error lines consistently.
function benchify_s(s) {
    return s.replace(/[^a-zA-Z0-9]/g, 'a');
}

it('benchify_s_exec_test_passing_0', () => {
  const args = superjson.parse('{"json":[["aaO"]]}');

  benchify_s(...args);
});

line.includes('Cannot resolve module') ||
line.includes('Module not found') ||
line.includes('Cannot resolve import');
Expand Down