Compare commits

...

1 Commits

Author SHA1 Message Date
Sonarly Claude Code c856e01e43 LogicFunction GraphQL schema missing builtHandlerPath field
https://sonarly.com/issue/4132?type=bug

The builtHandlerPath field was removed from the LogicFunction GraphQL DTO during a refactoring, but older frontend clients (v1.18.0) still query for it, causing a GraphQL validation error on the /metadata endpoint.

Fix: Re-add the builtHandlerPath field to the LogicFunctionDTO GraphQL ObjectType and include it in the flat-to-DTO mapping function. The field already exists in the LogicFunctionEntity database column, so the data is available. This restores backward compatibility so that older frontend clients querying builtHandlerPath will receive a valid response instead of a GraphQL validation error. The fix involves two changes:
1. Add builtHandlerPath as a @Field() decorated property to LogicFunctionDTO in logic-function.dto.ts
2. Map builtHandlerPath from flatLogicFunction in from-flat-logic-function-to-logic-function-dto.util.ts
2026-02-20 15:10:19 +00:00
3 changed files with 212 additions and 0 deletions
+207
View File
@@ -0,0 +1,207 @@
# Bug #4132:
## CRITICAL: Working Directory
Your working directory is `/work/worktrees/twentyhq-twenty-wt-3023`. This is your primary repository (`twentyhq/twenty`).
All edits MUST be performed within this directory.
## Sentry Error Details (TOON format)
Error information from Sentry (TOON = compact CSV-like format for lists):
```
event_info:
title: Cannot query field 'builtHandlerPath' on type 'LogicFunction'. Did you mean 'sourceHandlerPath'?: Cannot query field 'builtHandlerPath' on type 'LogicFunction'. Did you mean 'sourceHandlerPath'?
type: error
platform: javascript
culprit: /welcome
release: {'id': 1678867630; 'version': 'v1.18.0'; 'status': 'open'; 'shortVersion': 'v1.18.0'; 'versionInfo': {'package': None; 'version': {'raw': 'v1.18.0'}; 'description': 'v1.18.0'; 'buildHash': None}; 'ref...
user:
geo: country_code=AR, city=Buenos Aires, region=Argentina
exceptions[1]{type,value,mechanism}:
Cannot query field 'builtHandlerPath' on type 'Log...,Cannot query field 'builtHandlerPath' on type 'LogicFunction'. Did you mean 'sourceHandlerPath'?,handled=True
stack_frames[5]:
[+] /assets/index-DWghFydJ.js:3032:6887
fn: ? (module: assets/index-DWghFydJ)
3033: Copyright (c) 2018 Jed Watson.
3034: Licensed under the MIT License (MIT), see
3035: http://jedwatson.github.io/classnames
3036: ... ansition-show-delay"));G.current=setTimeout(()=>{he(!1),_e(null),U?.()},fn+25)}},[ve]);const tt=fn=>{ye(je=>iwe(je,fn)?je:fn)},Z=(fn=h)=>{ty ...
3037: ... ow:!0,place:"bottom",positionStrategy:"absolute",delay:u4.mediumDelay,isOpen:!0,children:n?Fe(GFn,{children:h}):h})}),document.body)]})};/**
[+] /assets/index-DWghFydJ.js:5838:15848
fn: TRo (module: assets/index-DWghFydJ)
5839: mutation AddQueryToEventStream($input: AddQuerySubscriptionInput!) {
5840: addQueryToEventStream(input: $input)
5841: }
5842: `,MKn=Ee`
5843: mutation RemoveQueryFromEventStream(
[+] /assets/index-DWghFydJ.js:5838:15130
fn: Object.bJn [as withScope] (module: assets/index-DWghFydJ)
5839: mutation AddQueryToEventStream($input: AddQuerySubscriptionInput!) {
5840: addQueryToEventStream(input: $input)
5841: }
5842: `,MKn=Ee`
5843: mutation RemoveQueryFromEventStream(
[+] /assets/index-DWghFydJ.js:5838:14523
fn: yJn.withScope (module: assets/index-DWghFydJ)
5839: mutation AddQueryToEventStream($input: AddQuerySubscriptionInput!) {
5840: addQueryToEventStream(input: $input)
5841: }
5842: `,MKn=Ee`
5843: mutation RemoveQueryFromEventStream(
[+] /assets/index-DWghFydJ.js:3032:6901
fn: ? (module: assets/index-DWghFydJ)
3033: Copyright (c) 2018 Jed Watson.
3034: Licensed under the MIT License (MIT), see
3035: http://jedwatson.github.io/classnames
3036: ... delay"));G.current=setTimeout(()=>{he(!1),_e(null),U?.()},fn+25)}},[ve]);const tt=fn=>{ye(je=>iwe(je,fn)?je:fn)},Z=(fn=h)=>{ty(ge),Pe?on(!0) ...
3037: ... ow:!0,place:"bottom",positionStrategy:"absolute",delay:u4.mediumDelay,isOpen:!0,children:n?Fe(GFn,{children:h}):h})}),document.body)]})};/**
request:
url: https://ventixsolutions.twenty.com/welcome
contexts:
browser: browser=Chrome 143.0.0; name=Chrome; version=143.0.0
device: family=Mac; model=Mac; brand=Apple
os: os=Mac OS X >=10.15.7; name=Mac OS X; version=>=10.15.7
breadcrumbs_fetch[10]{ts,method,url,status}:
14:52:28,POST,https://ventixsolutions.twenty.com/graphql,200
14:52:28,POST,https://ventixsolutions.twenty.com/metadata,200
14:52:29,POST,https://ventixsolutions.twenty.com/graphql,200
14:52:29,POST,https://ventixsolutions.twenty.com/graphql,200
14:52:29,POST,https://ventixsolutions.twenty.com/graphql,200
14:52:29,POST,https://ventixsolutions.twenty.com/metadata,200
14:52:29,POST,https://ventixsolutions.twenty.com/graphql,200
14:52:30,POST,https://ventixsolutions.twenty.com/graphql,200
14:52:30,POST,https://ventixsolutions.twenty.com/graphql,200
14:52:30,POST,https://ventixsolutions.twenty.com/metadata,200
breadcrumbs_console[38]{ts,level,msg}:
14:52:28,i,UNAUTHENTICATED; triggering token renewal
14:52:28,i,UNAUTHENTICATED; triggering token renewal
14:52:28,i,UNAUTHENTICATED; triggering token renewal
14:52:29,d,%cCannot query field "renewToken" on type "Mutation". color: #F51818; font-weight: lighter
14:52:29,d,%cUnknown type "AuthTokenPair". color: #F51818; font-weight: lighter
14:52:29,d,%cUnknown type "AuthToken". color: #F51818; font-weight: lighter
14:52:29,d,HEADERS:
14:52:29,d,VARIABLES [object Object]
14:52:29,d,QUERY mutation RenewToken($appToken: String!) { renewToken(appToken: $appToken) { tokens { ...
14:52:29,d,ERRORS [object Object];[object Object];[object Object]
14:52:29,i,Failed to renew token; triggering unauthenticated error from handleTokenRenewal
14:52:29,i,onUnauthenticatedError; resetting state
14:52:29,w,Uncompiled message detected! Message: > Open command menu That means you use raw catalog or your c...
14:52:29,d,%cCannot query field "renewToken" on type "Mutation". color: #F51818; font-weight: lighter
14:52:29,d,%cUnknown type "AuthTokenPair". color: #F51818; font-weight: lighter
14:52:29,d,%cUnknown type "AuthToken". color: #F51818; font-weight: lighter
14:52:29,d,HEADERS:
14:52:29,d,VARIABLES [object Object]
14:52:29,d,QUERY mutation RenewToken($appToken: String!) { renewToken(appToken: $appToken) { tokens { ...
14:52:29,d,ERRORS [object Object];[object Object];[object Object]
14:52:29,i,Failed to renew token; triggering unauthenticated error from handleTokenRenewal
14:52:29,i,onUnauthenticatedError; resetting state
14:52:29,i,tokenPair is undefined
14:52:29,d,%cCannot query field "renewToken" on type "Mutation". color: #F51818; font-weight: lighter
14:52:29,d,%cUnknown type "AuthTokenPair". color: #F51818; font-weight: lighter
14:52:29,d,%cUnknown type "AuthToken". color: #F51818; font-weight: lighter
14:52:29,d,HEADERS:
14:52:29,d,VARIABLES [object Object]
14:52:29,d,QUERY mutation RenewToken($appToken: String!) { renewToken(appToken: $appToken) { tokens { ...
14:52:29,d,ERRORS [object Object];[object Object];[object Object]
14:52:29,i,Failed to renew token; triggering unauthenticated error from handleTokenRenewal
14:52:29,i,onUnauthenticatedError; resetting state
14:52:29,i,tokenPair is undefined
14:52:29,d,HEADERS:
14:52:29,d,VARIABLES [object Object]
14:52:29,d,QUERY mutation RenewToken($appToken: String!) { renewToken(appToken: $appToken) { tokens { ...
14:52:29,d,RESULT [object Object]
14:52:29,i,setTokenPair from handleTokenRenewal
breadcrumbs_navigation[1]{ts,from,to}:
14:52:29,/objects/facturas?viewId=dc4c104d-0791-441e-be86-22c08d80a3d...,/welcome
breadcrumbs_sentry.transaction[1]{ts,type,level,msg}:
14:52:29,default,i,cafc56b1b423479f843c7d948352fdf3
```
## Severity Assessment
After analyzing the bug, determine severity independently based on your analysis:
- **critical**: User CANNOT complete a critical task. Crashes, core feature broken, data loss risk.
- **medium**: User CAN complete tasks but degraded experience. Non-critical feature broken, workaround exists.
- **low**: User unlikely to notice. Cosmetic, rare edge case, transient error that auto-recovers.
Your severity assessment in the output JSON is the FINAL severity that will be used.
## STRICT GIT RULES (violations = failed run)
- You are already on the correct fix branch — do NOT run `git checkout`, `git switch`, or `git merge`
- **NEVER run `git merge`** — merging other branches (feature branches, main, etc.) is FORBIDDEN
- **NEVER run `git checkout` on a different branch** — stay on your current branch at all times
- **NEVER run `git rebase`** — rebasing is not needed and can corrupt the worktree
- If the code you need to fix is not on this branch, fix the code that IS on this branch
or report that the fix cannot be applied — do NOT merge or pull in other branches
- **NEVER run `git add`, `git commit`, or `git push`** — the system handles all git write operations automatically after your analysis
- Only allowed git commands: `git blame`, `git log`, `git diff`, `git show` (read-only)
## Your Task (in this order)
1. **Find the Root Cause**
- Locate the exact file and line where the bug originates
- Understand why this error occurs
2. **Git Blame Analysis**
- Use `git blame` to find the commit that introduced this bug
- Note the commit SHA, author, and date
3. **Fix the Bug**
- Implement a **minimal, targeted fix** — only change what's necessary to resolve this specific error
- **NEVER modify shared/generic utilities, base classes, or ORM internals** to work around a missing field or feature.
Instead, fix the specific code paths that trigger the error (e.g. add a guard/try-catch in the caller).
Changing a generic utility to silently skip errors is ALWAYS wrong — it masks future bugs.
- Do NOT refactor surrounding code, add new features, or make unrelated improvements
- Do NOT build new components, screens, or functionality — only fix the reported error
- Add appropriate error handling if needed
- Do NOT run any git write commands (`git add`, `git commit`, `git push`) — the system handles committing and pushing automatically after your analysis
4. **Output Structured Analysis**
At the end of your response, output a JSON block between these markers:
```
SONARLY_ANALYSIS_START
{
"title": "User-focused title (max 60 chars)",
"severity": "critical|medium|low",
"summary": "1-2 sentence summary of the bug",
"user_impact": "Who was impacted and how they were impacted",
"evidence": { // Each code item: file (relative path from repo root), line (integer), snippet (faulty code, max ~10 lines). Multiple items for multiple files. {} if no evidence.
"code": [
{"file": "src/checkout/process.py", "line": 42, "snippet": "def process_order(order_id):\n orders = db.query(\"SELECT * FROM orders\") # missing WHERE clause"}
]
},
"root_cause": {
"explanation": "Root cause explanation. Use plain text only — NO bold, italic, or code backticks. When listing multiple points, use a numbered list (1. 2. 3.) with each item on its own line. Include who introduced it (git blame author), when (date), and why.",
"blame": {
"commit_sha": "abc123def (the full commit SHA from git blame, or null if unknown)",
"author": "Author Name (from git blame output, or null if unknown)",
"date": "2026-01-15 (date from git blame, or null if unknown)",
"commit_url": "https://github.com/{owner}/{repo}/commit/{sha} (build from git remote get-url origin + sha, strip any access token, or null)",
"explanation": "Brief explanation of when/who introduced the bug (e.g. Added in commit abc123 by John on Jan 15)"
}
},
"suggested_fix": {
"explanation": "What the fix does and why it solves the problem. Use plain text only — NO bold, italic, or code backticks. When listing multiple steps, use a numbered list (1. 2. 3.) with each item on its own line.",
"files_changed": ["path/to/file.py", "path/to/other.py (list of file paths you created or modified in the fix)"]
}
}
SONARLY_ANALYSIS_END
```
CRITICAL: The JSON block is the ONLY part of your response shown to the user.
Everything outside the SONARLY_ANALYSIS markers is discarded. Put ALL investigation details,
evidence (code snippets and log lines), and findings INSIDE the JSON fields,
especially root_cause.explanation, and summary. Do NOT write a separate investigation summary before the JSON.
IMPORTANT: The JSON between SONARLY_ANALYSIS_START and SONARLY_ANALYSIS_END must be valid JSON.
## Critical: ALWAYS output the analysis JSON
You MUST output SONARLY_ANALYSIS_START...SONARLY_ANALYSIS_END even if you could not find the code or fix the bug.
If you cannot locate the relevant code or create a fix,
explain what you found in the `root_cause.explanation` field.
A run without the analysis JSON is a FAILED run — never end without it.
Don't ask any questions to the user
@@ -64,6 +64,10 @@ export class LogicFunctionDTO {
@Field()
sourceHandlerPath: string;
@IsString()
@Field()
builtHandlerPath: string;
@IsString()
@Field()
handlerName: string;
@@ -14,6 +14,7 @@ export const fromFlatLogicFunctionToLogicFunctionDto = ({
runtime: flatLogicFunction.runtime,
timeoutSeconds: flatLogicFunction.timeoutSeconds,
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
builtHandlerPath: flatLogicFunction.builtHandlerPath,
handlerName: flatLogicFunction.handlerName,
toolInputSchema: flatLogicFunction.toolInputSchema ?? undefined,
isTool: flatLogicFunction.isTool,