Skip to content

fix: clarify bodyless Confluence content errors#206

Merged
pchuri merged 2 commits into
mainfrom
fm/fix-folder-read-r9
Jun 24, 2026
Merged

fix: clarify bodyless Confluence content errors#206
pchuri merged 2 commits into
mainfrom
fm/fix-folder-read-r9

Conversation

@pchuri

@pchuri pchuri commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Intent

Fix a reproduced crash where 'confluence read'/'edit'/'update' die with an opaque 'TypeError: Cannot read properties of undefined (reading value)' when the target content has no body (e.g. a Confluence folder, creatable via 'confluence create --type folder'). Root cause: three unguarded accesses to response.data.body.storage.value in lib/confluence-client.js — readPage, updatePage's reuse-existing-content path, and getPageForEdit. Folder content has no body.storage so .value throws; 'confluence info' already works on folders via the null-safe normalizePage, making this an internal inconsistency. Fix: added a shared helper requireStorageBody(data, pageId) that null-safely reads body.storage.value and throws a clear, consistent, actionable message ('Page has no readable body (it may be a folder or an unsupported content type).') instead of the cryptic TypeError, and routed all three sites through it. Deliberately kept one shared helper for message consistency; normal pages with a body are intentionally unchanged. Added focused regression tests in tests/confluence-client.test.js ('bodyless content (folder) handling') covering readPage, getPageForEdit, and the updatePage reuse-content path, asserting the clear message and that the TypeError no longer surfaces. Full suite (747 tests) green and eslint clean.

What Changed

  • Added a shared storage-body guard so Confluence folders and other bodyless content return a clear error instead of an opaque TypeError.
  • Applied the guard to read, edit, and title-only update flows while preserving normal page storage-body behavior.
  • Documented the bodyless-content behavior and added focused regression coverage for the affected Confluence client paths.

Risk Assessment

✅ Low: The change is narrowly scoped to replacing three unsafe body lookups with a null-safe helper and focused regression coverage, and I found no material risks introduced by the branch.

Testing

After fixing the setup issue with npm ci, the focused regression selector and full tests/confluence-client.test.js passed; the CLI transcript shows read, edit, and title-only update now return the clear bodyless-content error with no TypeError, while normal page read/edit/update still succeed and title-only update reuses the existing storage body. node_modules was removed afterward and the worktree is clean.

Evidence: Confluence CLI bodyless and normal transcript
# Confluence CLI Bodyless And Normal Body Evidence
Stub API: http://127.0.0.1:56442/rest/api
Stub content 123: folder-like content with body: {} and no body.storage.value.
Stub content 456: normal page with body.storage.value = <p>Storage body</p>.
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56442 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js read 123 --format storage
exit: 1
stdout:
(empty)
stderr:
Error: Page 123 has no readable body (it may be a folder or an unsupported content type).
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56442 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js edit 123
exit: 1
stdout:
(empty)
stderr:
Error: Page 123 has no readable body (it may be a folder or an unsupported content type).
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56442 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js update 123 --title Renamed folder
exit: 1
stdout:
(empty)
stderr:
Error: Page 123 has no readable body (it may be a folder or an unsupported content type).
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56442 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js read 456 --format storage
exit: 0
stdout:
<p>Storage body</p>
stderr:
(empty)
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56442 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js edit 456
exit: 0
stdout:
Page Information:
Title: Normal Page
ID: 456
Version: 7
Space: Engineering (ENG)

Page Content:
<p>Storage body</p>
stderr:
(empty)
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56442 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js update 456 --title Renamed page
exit: 0
stdout:
✅ Page updated successfully!
Title: Renamed page
ID: 456
Version: 8
URL: http://127.0.0.1:56442/pages/456
stderr:
(empty)
Server requests observed:
[
  {
    "method": "GET",
    "url": "/rest/api/content/123?expand=body.storage"
  },
  {
    "method": "GET",
    "url": "/rest/api/content/123?expand=body.storage,version,space"
  },
  {
    "method": "GET",
    "url": "/rest/api/content/123?expand=body.storage,version,space"
  },
  {
    "method": "GET",
    "url": "/rest/api/content/456?expand=body.storage"
  },
  {
    "method": "GET",
    "url": "/rest/api/content/456?expand=body.storage,version,space"
  },
  {
    "method": "GET",
    "url": "/rest/api/content/456?expand=body.storage,version,space"
  },
  {
    "method": "PUT",
    "url": "/rest/api/content/456"
  }
]
Normal page PUT bodies captured:
[
  {
    "id": "456",
    "type": "page",
    "title": "Renamed page",
    "space": {
      "key": "ENG",
      "name": "Engineering"
    },
    "body": {
      "storage": {
        "value": "<p>Storage body</p>",
        "representation": "storage"
      }
    },
    "version": {
      "number": 8
    }
  }
]
Old TypeError text surfaced: no
Unexpected PUT during bodyless title-only update: no
Overall result: PASS
Evidence: Bodyless folder CLI transcript
# Bodyless Confluence Content CLI Evidence
Stub API: http://127.0.0.1:56388/rest/api
Stub response for GET /rest/api/content/123: folder-like content with body: {} and no body.storage.value.
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56388 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js read 123 --format storage
exit: 1
stdout:
(empty)
stderr:
Error: Page 123 has no readable body (it may be a folder or an unsupported content type).
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56388 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js edit 123
exit: 1
stdout:
(empty)
stderr:
Error: Page 123 has no readable body (it may be a folder or an unsupported content type).
$ CONFLUENCE_AUTH_TYPE=none CONFLUENCE_PROTOCOL=http CONFLUENCE_DOMAIN=127.0.0.1:56388 CONFLUENCE_API_PATH=/rest/api CONFLUENCE_CLI_ANALYTICS=false node bin/index.js update 123 --title Renamed folder
exit: 1
stdout:
(empty)
stderr:
Error: Page 123 has no readable body (it may be a folder or an unsupported content type).
Server requests observed:
[
  {
    "method": "GET",
    "url": "/rest/api/content/123?expand=body.storage"
  },
  {
    "method": "GET",
    "url": "/rest/api/content/123?expand=body.storage,version,space"
  },
  {
    "method": "GET",
    "url": "/rest/api/content/123?expand=body.storage,version,space"
  }
]
Old TypeError text surfaced: no
Unexpected PUT during title-only update: no
Overall result: PASS

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • npm test -- --runTestsByPath tests/confluence-client.test.js -t &#34;bodyless content \\(folder\\) handling|readPage should return storage content when format is storage|updatePage with format=\\\&#34;auto\\\&#34; converts plain text to storage&#34; initially exposed missing local dependencies (jest: command not found).
  • npm ci to install project dependencies for testing.
  • npm test -- --runTestsByPath tests/confluence-client.test.js -t &#34;bodyless content \\(folder\\) handling|readPage should return storage content when format is storage|updatePage with format=\\\&#34;auto\\\&#34; converts plain text to storage&#34; after dependency install.
  • node &lt;&lt;&#39;NODE&#39; ... evidence generator running real node bin/index.js read/edit/update commands against a local HTTP Confluence stub for bodyless folder content and normal page content; transcript saved under the requested evidence directory.
  • npm test -- --runTestsByPath tests/confluence-client.test.js.
  • rm -rf node_modules cleanup, followed by git status --short and evidence-directory checks.
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

pchuri and others added 2 commits June 24, 2026 19:56
read/edit/update commands crashed with an opaque
"TypeError: Cannot read properties of undefined (reading 'value')"
when the target content has no body.storage, such as a Confluence
folder. Guard the three storage-body accesses in readPage, updatePage
(reuse-content path), and getPageForEdit via a shared requireStorageBody
helper that surfaces an actionable message instead.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@pchuri pchuri merged commit 62fee88 into main Jun 24, 2026
6 checks passed
github-actions Bot pushed a commit that referenced this pull request Jun 24, 2026
## [2.14.1](v2.14.0...v2.14.1) (2026-06-24)

### Bug Fixes

* **api:** prevent cross-origin credential leakage ([#207](#207)) ([1d614b2](1d614b2))
* clarify bodyless Confluence content errors ([#206](#206)) ([62fee88](62fee88))
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 2.14.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant