[GH-ISSUE #5994] [Bug] Screenshot origin-scope refusal recommends unrelated installation diagnostics #3662

Closed
opened 2026-10-31 00:42:49 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 21, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5994

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Process capture or runtime observation

Observed behavior

A screenshot capture whose current main frame is outside allowed_origins correctly refuses the capture, but both its message and remediation say “Analysis could not complete. Run rea doctor, then try again.” The known policy reason survives as target_not_allowed; the applicable origin/target-selection recovery does not. This reproduced through the production screenshot provider and shared error projection with a permitted discovery target and a disallowed current-frame URL.

Reproduction

Run from the source checkout with its locked dependencies installed. Save the following focused test as tests/boundary/browser/repro.test.ts and run:

node node_modules/vitest/vitest.mjs run tests/boundary/browser/repro.test.ts --maxWorkers 1

The test characterizes the incorrect behavior, so its assertions pass on this revision. The self-contained body below was replayed independently after the combined six-case run; its assertions passed.

import { expect, it } from 'vitest';
import { CdpBrowserProvider } from '../../../src/browser/CdpBrowserProvider.js';
import { projectAnalysisError } from '../../../src/domain/analysisErrorProjection.js';
import { captureWebScreenshotInputSchema } from '../../../src/domain/webScreenshot.js';
import { startFakeCdpBrowser } from '../../fixtures/fakeCdpBrowser.js';

it('projects origin denial as doctor advice through screenshot provider', async () => {
  const browser = await startFakeCdpBrowser({ attachedFrameUrl: 'https://outside.invalid/page' });
  const provider = new CdpBrowserProvider();
  try {
    const result = await provider.captureScreenshot(captureWebScreenshotInputSchema.parse({ cdp_endpoint: browser.endpoint, target_id: 'allowed-page', allowed_origins: [browser.allowedOrigin] }));
    expect(result.ok).toBe(false);
    if (result.ok) throw new Error('Expected origin refusal');
    const projection = projectAnalysisError(result.error);
    expect(projection).toMatchObject({ code: 'target_unavailable', details: { reason: 'target_not_allowed' } });
    expect(projection.remediation.action).toContain('rea doctor');
    console.log('ORIGIN', JSON.stringify(projection));
  } finally { await provider.close(); await browser.close(); }
});

The existing fixture supplies a real loopback HTTP/WebSocket endpoint and valid discovery metadata. It simulates Page.getFrameTree reporting an out-of-scope document. No real Chrome/Electron executable or CLI/MCP transport was exercised.

Expected behavior

Explain that the selected current document is outside the request's permitted origin scope, and give an applicable action such as selecting a permitted document or explicitly adjusting the origin list when intended. Keep the refusal effective. The browser scope contract excludes frames outside the selected origin scope. The screenshot guard knows this condition. Host prerequisite checks cannot change the document origin or caller's scope.

Impact and scope

P3: wrong diagnostic wording and recovery guidance for a correctly refused request. The selected origin policy remains enforced, and details.reason remains available to callers. No invalid capture success, data loss, failed agent loop, or successful real-browser recovery was observed. Callers can interpret the reason and inspect the page/request scope manually; that recovery was not executed here.

REA version

rea-agents 6.7.0; source revision 52415975942a4b9c53a817915b313ccc404f280e.

Runtime and platform

Node.js v26.12.0 and repository-pinned v24.18.0; macOS 27.0.1 arm64; locked Vitest 5.0.3. Each standalone test was replayed under both Node versions. Source tests with existing dependencies; no build performed.

Target and artifact context

One allowed discovered CDP page; its current main-frame response reports https://outside.invalid/page, excluded by the request origin list.

Interface

Other

Earliest failure stage

Transport or result projection

Relevant output or evidence

The provider boundary returns an error whose shared projection is:

{"code":"target_unavailable","category":"unavailable","message":"Analysis could not complete. Run `rea doctor`, then try again.","retryable":false,"remediation":{"action":"Analysis could not complete. Run `rea doctor`, then try again."},"details":{"operation":"capture_web_screenshot","reason":"target_not_allowed"}}

The focused test passed and both provider and fixture closed normally. This directly establishes the origin-refusal diagnostic; public CLI/MCP serialization is source-derived.

Typed outcome or recovery expected

Keep the policy refusal and a target-unavailability outcome, while naming the origin-scope condition and an applicable next step. The same target_not_allowed reason also represents unrelated conditions, so a universal origin-specific message for every producer would misdiagnose other tools.

Analysis or suspected cause

Source-derived: captureCdpScreenshot throws target_not_allowed without detail when its current main frame cannot be authorized. observationFailureMessage supplies no default for that reason, and presentation falls through to doctor advice. Preserving context at the scope-checking producer would allow accurate recovery without mislabeling Inspector or worker-policy refusals.

Additional context

Fetched main 25e1a24a3ed3671a0148757555f18d16c29d936a leaves the relevant producer and recovery behavior unchanged. Later shared cleanup/projection edits only avoid duplicating captured command output; these cases carry no captured command output. No newer runtime was built or executed. Last known good version: NOT_ENOUGH_INFO; none established. Compared #5753: that issue requires attachment-state/runtime-role recovery at Inspector guards; changing those guards does not explain screenshot origin denial, and origin advice would be wrong for them. #5724 covers target_changed after navigation, #5947 covers detail suppressing existing target_not_found recovery, #5946 covers an unresolved environment input, and #5954 covers runtime retention-budget classification. Closed #3126 and PRs #3140/#3143 concern detected service workers; PR #5933 concerns unreadable frame worker state. This report intentionally covers only the reproduced screenshot origin-scope condition.

Originally created by @coygeek on GitHub (Oct 21, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5994 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Process capture or runtime observation ### Observed behavior A screenshot capture whose current main frame is outside `allowed_origins` correctly refuses the capture, but both its message and remediation say “Analysis could not complete. Run `rea doctor`, then try again.” The known policy reason survives as `target_not_allowed`; the applicable origin/target-selection recovery does not. This reproduced through the production screenshot provider and shared error projection with a permitted discovery target and a disallowed current-frame URL. ### Reproduction Run from the source checkout with its locked dependencies installed. Save the following focused test as `tests/boundary/browser/repro.test.ts` and run: ```sh node node_modules/vitest/vitest.mjs run tests/boundary/browser/repro.test.ts --maxWorkers 1 ``` The test characterizes the incorrect behavior, so its assertions pass on this revision. The self-contained body below was replayed independently after the combined six-case run; its assertions passed. ```ts import { expect, it } from 'vitest'; import { CdpBrowserProvider } from '../../../src/browser/CdpBrowserProvider.js'; import { projectAnalysisError } from '../../../src/domain/analysisErrorProjection.js'; import { captureWebScreenshotInputSchema } from '../../../src/domain/webScreenshot.js'; import { startFakeCdpBrowser } from '../../fixtures/fakeCdpBrowser.js'; it('projects origin denial as doctor advice through screenshot provider', async () => { const browser = await startFakeCdpBrowser({ attachedFrameUrl: 'https://outside.invalid/page' }); const provider = new CdpBrowserProvider(); try { const result = await provider.captureScreenshot(captureWebScreenshotInputSchema.parse({ cdp_endpoint: browser.endpoint, target_id: 'allowed-page', allowed_origins: [browser.allowedOrigin] })); expect(result.ok).toBe(false); if (result.ok) throw new Error('Expected origin refusal'); const projection = projectAnalysisError(result.error); expect(projection).toMatchObject({ code: 'target_unavailable', details: { reason: 'target_not_allowed' } }); expect(projection.remediation.action).toContain('rea doctor'); console.log('ORIGIN', JSON.stringify(projection)); } finally { await provider.close(); await browser.close(); } }); ``` The existing fixture supplies a real loopback HTTP/WebSocket endpoint and valid discovery metadata. It simulates `Page.getFrameTree` reporting an out-of-scope document. No real Chrome/Electron executable or CLI/MCP transport was exercised. ### Expected behavior Explain that the selected current document is outside the request's permitted origin scope, and give an applicable action such as selecting a permitted document or explicitly adjusting the origin list when intended. Keep the refusal effective. The [browser scope contract](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/docs/browser-observation.md#L370) excludes frames outside the selected origin scope. [The screenshot guard](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/browser/CdpScreenshot.ts#L56-L59) knows this condition. Host prerequisite checks cannot change the document origin or caller's scope. ### Impact and scope P3: wrong diagnostic wording and recovery guidance for a correctly refused request. The selected origin policy remains enforced, and `details.reason` remains available to callers. No invalid capture success, data loss, failed agent loop, or successful real-browser recovery was observed. Callers can interpret the reason and inspect the page/request scope manually; that recovery was not executed here. ### REA version `rea-agents` 6.7.0; source revision `52415975942a4b9c53a817915b313ccc404f280e`. ### Runtime and platform Node.js v26.12.0 and repository-pinned v24.18.0; macOS 27.0.1 arm64; locked Vitest 5.0.3. Each standalone test was replayed under both Node versions. Source tests with existing dependencies; no build performed. ### Target and artifact context One allowed discovered CDP page; its current main-frame response reports https://outside.invalid/page, excluded by the request origin list. ### Interface Other ### Earliest failure stage Transport or result projection ### Relevant output or evidence The provider boundary returns an error whose shared projection is: ```json {"code":"target_unavailable","category":"unavailable","message":"Analysis could not complete. Run `rea doctor`, then try again.","retryable":false,"remediation":{"action":"Analysis could not complete. Run `rea doctor`, then try again."},"details":{"operation":"capture_web_screenshot","reason":"target_not_allowed"}} ``` The focused test passed and both provider and fixture closed normally. This directly establishes the origin-refusal diagnostic; public CLI/MCP serialization is source-derived. ### Typed outcome or recovery expected Keep the policy refusal and a target-unavailability outcome, while naming the origin-scope condition and an applicable next step. The same `target_not_allowed` reason also represents unrelated conditions, so a universal origin-specific message for every producer would misdiagnose other tools. ### Analysis or suspected cause Source-derived: [captureCdpScreenshot](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/browser/CdpScreenshot.ts#L56-L59) throws `target_not_allowed` without detail when its current main frame cannot be authorized. [observationFailureMessage](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/domain/browserObservationError.ts#L42-L60) supplies no default for that reason, and [presentation](https://github.com/morluto/rea/blob/52415975942a4b9c53a817915b313ccc404f280e/src/domain/analysisErrorPresentation.ts#L241-L308) falls through to doctor advice. Preserving context at the scope-checking producer would allow accurate recovery without mislabeling Inspector or worker-policy refusals. ### Additional context Fetched main `25e1a24a3ed3671a0148757555f18d16c29d936a` leaves the relevant producer and recovery behavior unchanged. Later shared cleanup/projection edits only avoid duplicating captured command output; these cases carry no captured command output. No newer runtime was built or executed. Last known good version: NOT_ENOUGH_INFO; none established. Compared #5753: that issue requires attachment-state/runtime-role recovery at Inspector guards; changing those guards does not explain screenshot origin denial, and origin advice would be wrong for them. #5724 covers target_changed after navigation, #5947 covers detail suppressing existing target_not_found recovery, #5946 covers an unresolved environment input, and #5954 covers runtime retention-budget classification. Closed #3126 and PRs #3140/#3143 concern detected service workers; PR #5933 concerns unreadable frame worker state. This report intentionally covers only the reproduced screenshot origin-scope condition.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3662
No description provided.