Bug: forgejo_issue_create/view/edit/close/etc. crash when assignees is null in the API response #29
Closed
opened 2026-08-18 03:02:22 +00:00 by david
·
1 comment
No Branch/Tag specified
main
feature/issue-264/verify-the-vision-tool-live-against-the-deepseek-a
feature/issue-263/list-the-vision-extension-in-the-repo-root-readme
feature/issue-262/write-extensions-vision-readme-md-the-10-section-p
feature/issue-261/wire-the-vision-extension-into-package-json-manife
feature/issue-260/implement-extensions-vision-index-ts-factory-regis
feature/issue-258/implement-extensions-vision-src-tool-ts-the-vision
feature/issue-257/implement-extensions-vision-src-client-ts-request
feature/issue-256/implement-extensions-vision-src-usage-ts-usage-map
feature/issue-255/implement-extensions-vision-src-images-ts-read-val
feature/issue-254/implement-extensions-vision-src-config-ts-env-reso
feature/issue-253/implement-extensions-vision-src-errors-ts-toolerro
feature/issue-252/penpot-add-text-stages-zero-area-auto-width-text-p
feature/issue-216/add-the-penpot-skill-and-extension-to-the-repo-roo
feature/issue-217/register-the-penpot-tests-in-npm-test-complete-the
feature/issue-215/write-the-penpot-skill-md-core-workflow-token-conv
feature/issue-214/implement-and-run-fetch-penpot-docs-mjs-and-commit
feature/issue-213/validate-screenshot-reconstruction-against-the-liv
feature/issue-212/add-the-image-to-design-workflow-to-skills-penpot
feature/issue-211/validate-svg-import-icon-and-illustration-against
feature/issue-210/implement-the-penpot-add-svg-tool-with-svg-raw-fal
feature/issue-209/implement-the-svg-to-shapes-converter-in-src-svg-t
feature/issue-208/validate-component-instancing-against-the-live-ins
feature/issue-207/implement-penpot-instance-component-with-id-remapp
feature/issue-206/author-and-commit-the-component-library-artifact-u
feature/issue-205/implement-file-library-linking-and-validate-the-ex
feature/issue-204/implement-penpot-export-library-sse-uri-plus-artif
feature/issue-203/implement-penpot-import-library-multipart-upload-p
feature/issue-202/implement-the-transit-decoder-and-sse-stream-parse
feature/issue-201/validate-a-full-composed-screen-one-commit-one-rev
feature/issue-200/implement-penpot-add-image-with-media-upload
feature/issue-199/implement-asset-reference-resolution-plus-penpot-a
feature/issue-198/implement-penpot-add-frame-with-auto-layout-props
feature/issue-197/validate-asset-creation-atomicity-and-write-safety
feature/issue-196/implement-the-designated-target-write-guard-with-a
feature/issue-195/implement-penpot-commit-with-revn-tracking-conflic
feature/issue-194/implement-the-staged-changeset-store-and-the-colou
feature/issue-193/validate-read-primitives-against-the-live-penpot-i
feature/issue-192/implement-the-penpot-list-library-tool-with-name-t
feature/issue-191/implement-the-penpot-get-file-tool-pages-objects-a
feature/issue-190/implement-the-penpot-list-projects-tool-teams-and
feature/issue-189/implement-the-penpot-whoami-tool-and-wire-the-exte
feature/issue-188/implement-the-rpc-client-and-error-decoding-in-src
feature/issue-187/implement-penpot-url-penpot-token-resolution-in-sr
feature/issue-186/scaffold-the-penpot-extension-directory-and-regist
feature/issue-172/add-end-to-end-main-tests-for-the-fj-rg-tool-state
feature/issue-171/make-reminder-report-dynamic-install-skip-counts-r
feature/issue-170/wire-settings-json-filter-rewrite-into-dedupeandre
feature/issue-169/implement-buildpackagefilters-with-exhaustive-unit
feature/issue-168/refactor-preflight-to-skip-warn-for-missing-fj-rg
feature/issue-167/add-fj-rg-tool-detection-helpers-rgavailable-detec
feature/issue-148/reconcile-design-md-and-implementation-plan-with-t
feature/issue-146/verify-extension-load-behavior-with-and-without-mo
feature/issue-145/write-extensions-mongodb-readme-md
feature/issue-144/write-tool-description-promptsnippet-guidance-for
feature/issue-143/implement-index-ts-async-factory-lifecycle-with-te
feature/issue-142/implement-the-mongo-list-collections-tool-with-uni
feature/issue-141/implement-the-mongo-count-tool-with-unit-tests
feature/issue-140/implement-the-mongo-find-tool-with-unit-tests
feature/issue-139/implement-src-errors-ts-with-unit-tests-toolerror
feature/issue-138/implement-src-serialize-ts-with-unit-tests-ejson-t
feature/issue-136/implement-src-env-ts-with-unit-tests-mongodb-uri-r
feature/issue-135/register-the-mongodb-extension-in-the-repo-root-pa
feature/issue-133/initialize-the-extensions-mongodb-package-package
feature/issue-116/src-actions-ts-downloadrunlogs-zip-guarded-unzip-c
feature/issue-115/src-actions-ts-downloadjoblog-cache-first-attempt
feature/issue-114/src-actions-ts-metadata-queries-listactionruns-get
feature/issue-113/src-actionscache-ts-cache-paths-cache-first-read-w
feature/issue-112/add-zip-extraction-dependency-adm-zip-vs-yauzl
feature/issue-111/tracking-forgejo-actions-tooling-read-only-runs-jo
feature/issue-93/add-unit-tests-for-scripts-local-install-mjs-node
feature/issue-92/validate-install-local-end-to-end-on-the-dev-machi
feature/issue-90/implement-pi-registration-with-url-dedupe-and-relo
feature/issue-89/validate-install-local-from-a-scratch-clone-fresh
feature/issue-88/implement-git-pull-and-npm-install-steps-in-script
feature/issue-74/write-victorialogs-readme-md-and-reconcile-design
feature/issue-73/wire-up-index-ts-extension-factory-and-register-al
feature/issue-72/implement-logs-facets-tool-src-tools-facets-ts
feature/issue-71/implement-logs-hits-tool-src-tools-hits-ts
feature/issue-70/implement-logs-search-tool-src-tools-search-ts
feature/issue-69/implement-parsejsonlines-helper-in-src-client-ts
feature/issue-68/implement-victorialogsrequest-in-src-client-ts
feature/issue-67/implement-resolvebaseurl-in-src-env-ts
feature/issue-66/implement-totoolerror-in-src-errors-ts
feature/issue-65/implement-src-defaults-ts-shared-constants-and-app
feature/issue-64/scaffold-the-victorialogs-pi-extension-project
feature/issue-53/skip-issue-creation-for-chore-documentation-commit
feature/issue-45/fix-local-install-preflight-env-var-requirements-s
feature/issue-41/add-npm-run-local-install-script-to-update-and-ins
feature/issue-26/cross-reference-forgejo-list-milestones-from-issue
feature/issue-25/add-forgejo-milestone-delete-tool
feature/issue-24/add-forgejo-milestone-close-and-forgejo-milestone
feature/issue-23/add-forgejo-milestone-edit-tool
feature/issue-22/add-forgejo-milestone-view-tool
feature/issue-21/add-forgejo-list-milestones-tool
feature/issue-20/add-forgejo-milestone-create-tool
feature/issue-18/add-forgejo-label-create-tool
feature/issue-29/bug-forgejo-issue-create-view-edit-close-etc-crash
No results found.
Labels
No labels
bug
chore
documentation
enhancement
feature
ready
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
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
david/pi-extensions-and-skills#29
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
forgejo_issue_create,forgejo_issue_view,forgejo_issue_edit,forgejo_issue_close,forgejo_issue_reopen,forgejo_issue_assign,forgejo_issue_unassign,forgejo_issue_add_labels, and the equivalent PR tools all throwCannot read properties of null (reading 'length')whenever the Forgejo API returnsassignees: nullfor the issue/PR being formatted — which is the normal, valid response shape for any issue/PR with no assignees. The underlying API call succeeds; only the tool's response-formatting step crashes, which still surfaces as a hard tool failure to the caller.Background
This was discovered while using
forgejo_issue_createto file tracking issues in this repo: every call to create an issue with no assignees (the common case) returned the errorCannot read properties of null (reading 'length')even though the issue was actually created successfully server-side (confirmed via the raw REST API afterwards). This caused at least one accidental duplicate issue before the pattern was noticed and worked around by calling the raw Forgejo REST API directly instead of the extension's tools.Root cause (
extensions/forgejo/):"assignees": null(not[]) when an issue/PR has no assignees — this is normal API behavior, not a Forgejo server bug.src/issues.ts'sForgejoIssueinterface (andsrc/pulls.ts'sForgejoPullRequestinterface) typeassigneesasForgejoAssignee[]— nevernull/undefined.forgejoApiCall<T>()insrc/api.tsdoesJSON.parse(rawText) as T— a compile-time-only type assertion with no runtime validation. Soissue.assigneescan benullat runtime despite TypeScript believing it's always an array.formatIssue()andformatPullRequest()insrc/index.tsthen callissue.assignees.length/pr.assignees.lengthunconditionally (and.map(...)on the same field for thedetailsobject), which throws when the value isnull.This affects every tool that formats an issue or PR response whenever that issue/PR currently has no assignees — i.e. most issues, since assigning is opt-in.
Implementation Details
In
extensions/forgejo/src/index.ts:formatIssue()(around theissue.assignees.length > 0check and theassignees: issue.assignees.map(...)details field): guard both usages, e.g.(issue.assignees ?? []).length > 0and(issue.assignees ?? []).map((assignee) => assignee.login).formatPullRequest()(the equivalentpr.assignees.length > 0check andassignees: pr.assignees.map(...)details field): apply the same guard.ForgejoIssue.assigneesandForgejoPullRequest.assigneesinsrc/issues.ts/src/pulls.tstoForgejoAssignee[] | null, so the type system reflects what the API can actually return, rather than relying solely on defensive formatting code. If this widening is done, downstream call sites that assume a non-null array (e.g.assignIssue's/unassignIssue's callers, other formatters) should be re-checked for the same null-safety gap.tests/index.test.ts(or wherever tool-level formatting is tested) that mock a Forgejo API response withassignees: null(and separatelylabels: null, if that field has the same risk — checkformatIssue'sissue.labels.lengthusage too) and assert the tool call succeeds instead of throwing.Acceptance Criteria
forgejo_issue_create/_view/_edit/_close/_reopen/_assign/_unassign/_add_labels/_remove_labelsall succeed (no crash) when the Forgejo API response hasassignees: null.forgejo_pr_create/_view/_edit/_close/_assignall succeed (no crash) under the same condition.labelsinformatIssue/formatPullRequestif that field can also benullin practice (verify against the API, don't assume).assignees: nullresponse) and confirms it now passes.npm testandnpm run checkpass with no regressions.Test Plan
forgejoApiCallto return an issue/PR payload withassignees: null, call the corresponding tool'sexecute(), and assert it returns a successfulToolResult(not a thrown exception).npm test— confirm the new regression test passes and the full suite remains green.forgejo_issue_createwith noassigneeson a real repo and confirm it succeeds and returns the created issue's number/URL without error.pi-loop opened and merged a pull request for this issue: #32