Skip to content

fix(core): Make scoped workspace path errors actionable for agents - #37887

Open
bjorger wants to merge 2 commits into
masterfrom
agent-691-agents-agent-preview-fails-with-tool-call-error-while
Open

fix(core): Make scoped workspace path errors actionable for agents#37887
bjorger wants to merge 2 commits into
masterfrom
agent-691-agents-agent-preview-fails-with-tool-call-error-while

Conversation

@bjorger

@bjorger bjorger commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

When an agent passes a path outside its scoped workspace root (for example /tmp/ids.txt), the workspace tools reject the call with Path escapes workspace root: /tmp/ids.txt. The message does not name the root and does not say how to fix the call. The system prompt only says Filesystem access is scoped to <root>. and the tool schemas only say Path to the file to write. The model has no way to self-correct, and the user sees an opaque tool error in the agent preview.

This PR mirrors the guidance that Instance AI already gives its model, inside the shared @n8n/agents scoped workspace:

  • Rejection message (scoped-workspace.ts): the error now names the offending path, the workspace root, and the remedy:
    Path "/tmp/ids.txt" is outside the workspace root "/home/user/workspace". Use a path relative to the workspace root, e.g. "tmp/output.txt".
    The tool runtime returns this text to the model, so the model can retry with a path under the root on the next turn.
  • Workspace instructions (ScopedFilesystem.getInstructions): the text appended to the system prompt now explains that paths resolve against the root, that absolute paths must stay under the root, and that <root>/tmp is the place for scratch files.
  • Tool schemas (workspace_read_file, workspace_write_file, workspace_str_replace_file): the path parameter now says it is relative to the workspace root and that absolute paths must be under it.

The scope check itself does not change. Instance AI shares createScopedWorkspace and only inherits the new error text; it keeps its own prompt guidance. The four existing test assertions that matched the old message prefix now match the new message.

How to test

  1. Start an instance with the agent sandbox enabled (N8N_AGENTS_AI_SANDBOX_ENABLED=true plus a configured sandbox provider).
  2. Open an agent in the agent builder and start a preview conversation.
  3. Ask the agent: "Use your workspace tools to write the text hello to /tmp/hello.txt."
  4. Expected: the agent writes the file under <root>/tmp directly. If the agent still calls the tool with /tmp/hello.txt, the tool error names the workspace root and the agent retries with a path under the root and succeeds.
  5. Unit tests: cd packages/@n8n/agents && pnpm test src/workspace/__tests__/scoped-workspace.test.ts src/__tests__/workspace/scoped-workspace.test.ts

Related Linear tickets, Github issues, and Community forum posts

https://linear.app/n8n/issue/AGENT-691

Review / Merge checklist

  • I have seen this code, I have run this code, and I take responsibility for this code.
  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • PR Labeled with Backport to Beta, Backport to Stable, or Backport to v1 (if the PR is an urgent fix that needs to be backported)

🤖 PR Summary generated by AI

Made with Cursor

Review in cubic

Co-authored-by: Cursor <cursoragent@cursor.com>
@n8n-assistant

n8n-assistant Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

PR review overview

Based on ownership of the 14 changed files in this PR:

Ownership Files owned Share Source code Test files Misc
@n8n-io/ai 14 100% +24 / -5 +375 / -813 +0 / -0
Total 14 100% +24 / -5 +375 / -813 +0 / -0

@n8n-assistant n8n-assistant Bot added the n8n team Authored by the n8n team label Sep 4, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 6 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Shadow auto-approve: would auto-approve. Improves error messages and tool schema descriptions for scoped workspace tools to guide agents to use paths under the workspace root. The scope check itself is unchanged, making this a bounded, clearly beneficial UX improvement backed by updated tests.

Re-trigger cubic

@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 33.33333% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ages/@n8n/agents/src/workspace/scoped-workspace.ts 33.33% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@bjorger
bjorger requested a review from mike12345567 September 4, 2026 16:04
@bjorger
bjorger marked this pull request as ready for review September 4, 2026 16:04
@bjorger
bjorger enabled auto-merge September 4, 2026 16:04
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Instance AI Workflow Eval

Important

This eval does not re-run on new commits. To test your latest push, re-run it against the PR head:

gh workflow run ci-instance-ai-evals.yml -f pr=37887

…or use the Run workflow button and set pr = 37887.

Tip

🟢 All 25 units green over 3 runs; 5 flaky — see Failures below.

Gate: pass@k = 100% (every unit passes at least once across k runs) — 93.3% pass (70/75 trials over 25 units · k=3)

pass@3 100.0% · pass^3 85.9% · LangSmith experiment

Failures (5)

notification-router :: Before building the workflow, the agent established the inco — passed 2/3

The agent invented the payload field name urgency before building (never asked the user about it), and the user had to correct it to level in Turn 2; only the urgency levels (High/Medium/Low) were established via the pre-build question.

rest-api-data-pipeline/happy-path — passed 2/3

[builder_issue] Multiple criteria fail due to builder misconfiguration. (1) 'qui' filter missing: The Filter Posts node only checks $json.published === true — it has no condition filtering out titles containing 'qui'. As a result, posts with titles 'qui est esse' and 'nesciunt quid non qui' passed the filter and were posted to Slack. (2) Slack messages contain 'qui': Because the filter never removed them, the Slack requests clearly show messages with 'qui est esse' and 'nesciunt quid non qui' in the text — directly violating the requirement that none of the titles contain 'qui'. (3) No post count in message: The Slack text template is *{{ $json.title }}*\n{{ $json.id }}, which posts one individual message per post showing title and id — there is no aggregated summary with a count of remaining posts. (4) Channel not #api-digest: The channelId __rl.value is an empty string (""), so the channel was resolved to the eval-mock placeholder C00000000EVAL, not #api-digest. All four sub-requirements of this checklist item are violated.

rest-api-data-pipeline/all-filtered — passed 2/3

[builder_issue] The scenario requires all posts to be filtered out (because they contain 'qui' in the title) and then a Slack message stating '0 posts remain' to be posted. The workflow fails on two fronts: (1) The Filter Posts node's condition checks $json.published === true (boolean), not whether the title contains 'qui', so all 3 posts pass the filter and are NOT filtered out — they all flow to Post to Slack as individual post messages. (2) There is no branch, fallback node, aggregation, or counter in the workflow that would post a '0 posts remain' summary message when all items are filtered. Even if the filter had been correctly configured to exclude all posts, 0 items flowing into Post to Slack would simply cause that node to not execute at all — no summary message would be sent. The workflow sent 3 individual post messages instead of a single '0 posts remain' summary.

revises-plan-after-rejection/urgent-rows-only — passed 2/3

[builder_issue] The workflow crashed at the 'Read Leads' node with 'Can not get sheet 'By ID' with a value of 'undefined''. The documentId is configured as ={{ $vars.LEADS_SPREADSHEET_ID }}, but the variable LEADS_SPREADSHEET_ID is not defined in the test environment, so the expression resolves to undefined. This caused the node to abort before any data could be read, and all downstream nodes (Only Urgent, Post to Slack, Mark Posted) never ran. The success criteria require the run to complete without errors and for exactly the two Urgent rows to be posted to #urgent-alerts — neither condition is met.

workflow-data-table/happy-path — passed 2/3

[builder_issue] The workflow executes without errors and uses upsert to avoid duplicates — both requirements are met. All 4 workflows were correctly upserted with workflowId, workflowName, and tags fields. However, the checklist explicitly requires a data table called 'workflows', while the builder created (and configured) a table named 'Remote Workflow Metadata' (cachedResultName: "Remote Workflow Metadata", dataTableId: "K9TdgdKoz0fmfDL3"). The table name is wrong per the stated requirement.

Per-test-case results (8)
Workflow Status pass@3 pass^3
airtable-split-to-slack 3/3 100% 100%
notification-router 3/3 100% 88%
refuses-deprecated-chat-model 3/3 100% 100%
rest-api-data-pipeline 3/3 100% 30%
revises-plan-after-rejection 3/3 100% 86%
telegram-chatbot-memory-session 3/3 100% 100%
weather-alert 3/3 100% 100%
workflow-data-table 3/3 100% 30%

Workflow checks

Scored over 24 successful build(s). N/A = check did not apply to that workflow. Error = check could not be measured (e.g. judge timeout).

Dimension Check Kind Pass Fail N/A Error Pass rate
connection_topology handles_multiple_items llm 23 1 0 0 96%
parameter_correctness correct_node_operations llm 21 3 0 0 88%
parameter_correctness google_sheets_rlc_default_mode deterministic 2 1 21 0 67%
intent_match fulfills_user_request llm 19 5 0 0 79%
All workflow checks (4 failing of 35 checks)
Dimension Check Kind Pass Fail N/A Error Pass rate
structure has_nodes deterministic 24 0 0 0 100%
structure has_start_node deterministic 24 0 0 0 100%
structure has_trigger deterministic 24 0 0 0 100%
structure no_disabled_nodes deterministic 24 0 0 0 100%
connection_topology all_nodes_connected deterministic 24 0 0 0 100%
connection_topology error_routes_consistent deterministic 24 0 0 0 100%
connection_topology handles_multiple_items llm 23 1 0 0 96%
connection_topology no_unreachable_nodes deterministic 24 0 0 0 100%
connection_topology switch_fallback_output_enabled deterministic 3 0 21 0 100%
parameter_correctness correct_node_operations llm 21 3 0 0 88%
parameter_correctness expressions_reference_existing_nodes deterministic 6 0 18 0 100%
parameter_correctness google_sheets_rlc_default_mode deterministic 2 1 21 0 67%
parameter_correctness http_generic_auth_type_matches_prompt deterministic 0 0 24 0
parameter_correctness item_flow_independent_source_execute_once deterministic 0 0 24 0
parameter_correctness item_flow_paired_item_references deterministic 0 0 24 0
parameter_correctness no_empty_set_nodes deterministic 0 0 24 0
parameter_correctness no_invalid_from_ai deterministic 0 0 24 0
parameter_correctness valid_data_flow llm 24 0 0 0 100%
parameter_correctness valid_field_references deterministic 21 0 3 0 100%
parameter_correctness valid_node_config deterministic 24 0 0 0 100%
intent_match fulfills_user_request llm 19 5 0 0 79%
communication response_describes_changes_accurately llm 24 0 0 0 100%
ai_nodes agent_has_dynamic_prompt deterministic 6 0 18 0 100%
ai_nodes agent_has_language_model deterministic 6 0 18 0 100%
ai_nodes memory_properly_connected deterministic 6 0 18 0 100%
ai_nodes memory_session_key_expression deterministic 6 0 18 0 100%
ai_nodes tools_have_parameters deterministic 0 0 24 0
ai_nodes vector_store_has_embeddings deterministic 0 0 24 0
nodes_craftsmanship code_node_no_http_requests deterministic 3 0 21 0 100%
nodes_craftsmanship descriptive_node_names llm 24 0 0 0 100%
nodes_craftsmanship no_unnecessary_code_nodes llm 24 0 0 0 100%
efficiency no_excessive_build_failures deterministic 24 0 0 0 100%
security inbound_trigger_auth_defaults deterministic 6 0 18 0 100%
security no_hardcoded_credentials deterministic 0 0 24 0
security secrets_use_credentials_not_parameters deterministic 8 0 16 0 100%

…riptions

Co-authored-by: Cursor <cursoragent@cursor.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 8 files (changes from recent commits).

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Shadow auto-approve: would auto-approve. Improves scoped workspace tool error messages and schema descriptions to guide agents to paths under the workspace root, without changing scope enforcement. Bounded UX improvement backed by updated tests.

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed n8n team Authored by the n8n team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant