Skip to content

fix: handle JSON-encoded string for list parameters in MCP tools#76

Open
ej31 wants to merge 6 commits intomakeplane:canaryfrom
ej31:fix/list-param-json-string-deserialization
Open

fix: handle JSON-encoded string for list parameters in MCP tools#76
ej31 wants to merge 6 commits intomakeplane:canaryfrom
ej31:fix/list-param-json-string-deserialization

Conversation

@ej31
Copy link

@ej31 ej31 commented Mar 5, 2026

What's the problem?

Some MCP clients (e.g. Claude Code) serialize list parameters as JSON-encoded strings when invoking tools. This causes a Pydantic validation error at runtime:

1 validation error for call[add_work_items_to_module]
issue_ids
  Input should be a valid list [type=list_type, input_value='["660bb007-..."]', input_type=str]

The type annotation list[str] is correct and FastMCP generates the right JSON schema from it. The issue is that some clients wrap ["id1", "id2"] into a string '["id1", "id2"]' before sending it over the wire, and Pydantic rejects that.

Affected tools

  • add_work_items_to_module (modules.py)
  • add_work_items_to_cycle (cycles.py)
  • add_work_items_to_milestone (milestones.py)
  • remove_work_items_from_milestone (milestones.py)

Fix

Added a small runtime guard at the top of each affected function that calls json.loads() when the value arrives as a str. It's fully backward-compatible:

  • Client passes a proper list → works exactly as before
  • Client passes a JSON string → gets parsed into a list before use
# Some MCP clients serialize list parameters as JSON strings; handle both cases
if isinstance(issue_ids, str):
    issue_ids = json.loads(issue_ids)

The type annotation is intentionally kept as list[str] so the tool schema exposed to MCP clients stays unchanged.

Testing

Reproduced the failure with Claude Code where add_work_items_to_module was consistently erroring out. Confirmed it works correctly after the fix.

Also added unit tests (tests/test_list_param_fix.py) covering:

  • issue_ids passed as a JSON-encoded string → parsed and forwarded correctly
  • issue_ids passed as a native list → works as before

All 5 tests pass ✅

Summary by CodeRabbit

  • New Features

    • List parameters (issue IDs, assignees, labels, members, project IDs, relations, default values) now accept JSON-encoded strings or native lists, with clear validation and error messages for invalid inputs.
  • Tests

    • Added comprehensive unit tests covering JSON string parsing and validation across cycles, modules, milestones, epics, work items, relations, properties, and types.

Some MCP clients (e.g. Claude Code) serialize list parameters as
JSON-encoded strings when invoking tools. This caused a Pydantic
validation error in tools that accept `list[str]` parameters:

  Input should be a valid list [type=list_type,
  input_value='["uuid-..."]', input_type=str]

Affected tools:
- add_work_items_to_module (modules.py)
- add_work_items_to_cycle (cycles.py)
- add_work_items_to_milestone (milestones.py)
- remove_work_items_from_milestone (milestones.py)

Fix: add a runtime check at the start of each affected function that
deserializes the value with json.loads() when it arrives as a string,
preserving the original list[str] type annotation for schema generation.
@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a44bd073-a9ca-44a2-a707-b84e517ce104

📥 Commits

Reviewing files that changed from the base of the PR and between ac034c7 and 17c80ed.

📒 Files selected for processing (1)
  • tests/test_integration.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_integration.py

📝 Walkthrough

Walkthrough

Adds JSON-string parsing for multiple list-like parameters across plane_mcp tools so callers may pass either native lists or JSON-encoded strings; invalid JSON or wrong types now raise explicit ValueError exceptions. Public function signatures remain unchanged.

Changes

Cohort / File(s) Summary
Cycle Tools
plane_mcp/tools/cycles.py
add_work_items_to_cycle now accepts issue_ids as a JSON string or list; parses JSON and validates list[str], raising ValueError on failure.
Milestone Tools
plane_mcp/tools/milestones.py
add_work_items_to_milestone, remove_work_items_from_milestone parse issue_ids from JSON strings and validate list[str].
Module Tools
plane_mcp/tools/modules.py
create_module, update_module, add_work_items_to_module accept members/issue_ids as JSON strings or lists; parse and validate list[str].
Epic Tools
plane_mcp/tools/epics.py
create_epic, update_epic parse assignees and labels when provided as JSON strings; added json import and input validation.
Work Items
plane_mcp/tools/work_items.py
create_work_item, update_work_item parse assignees and labels from JSON strings and validate list[str].
Work Item Relations
plane_mcp/tools/work_item_relations.py
create_work_item_relation accepts issues as a JSON string or list; parses and validates list[str].
Work Item Types
plane_mcp/tools/work_item_types.py
create_work_item_type, update_work_item_type parse project_ids from JSON strings and validate list[str].
Work Item Properties
plane_mcp/tools/work_item_properties.py
create_work_item_property, update_work_item_property parse default_value when provided as a JSON string and validate the resulting list.
Tests — New
tests/test_list_param_fix.py
New comprehensive tests asserting parsing of JSON-encoded list parameters across modules and that client calls receive native lists.
Tests — Small edits
tests/test_integration.py, tests/test_oauth_security.py
Narrowed exception handling for JSON parse in extract_result; minor import formatting change.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~23 minutes

Poem

🐰 I found a JSON string in spring,
I nudged it, gave it parsing wing,
It hopped to lists, so neat and bright,
Now every tool accepts its flight,
Hooray — we code and softly sing! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately describes the main change: adding support for JSON-encoded string parameters in MCP tool list parameters.
Docstring Coverage ✅ Passed Docstring coverage is 97.83% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

ej31 added 3 commits March 5, 2026 12:17
Covers the case where MCP clients pass list parameters as JSON strings.
Tests verify both the string-input and native-list-input paths for:
- add_work_items_to_module
- add_work_items_to_cycle
- add_work_items_to_milestone
- remove_work_items_from_milestone
Extends the fix from PR makeplane#76 to cover all remaining tool parameters that
accept list[str] and may receive JSON-encoded strings from MCP clients.

Previously fixed (PR makeplane#76):
- add_work_items_to_module (modules.py)
- add_work_items_to_cycle (cycles.py)
- add_work_items_to_milestone (milestones.py)
- remove_work_items_from_milestone (milestones.py)

Newly fixed parameters:
- create_work_item / update_work_item: assignees, labels (work_items.py)
- create_module / update_module: members (modules.py)
- create_work_item_relation: issues (work_item_relations.py)
- create_epic / update_epic: assignees, labels (epics.py)
- create_work_item_property / update_work_item_property: default_value
- create_work_item_type / update_work_item_type: project_ids

Also backfills the four PR makeplane#76 guards with proper json.JSONDecodeError
handling (raise ValueError with chained exception) for consistency.

Adds import json to: work_items.py, work_item_relations.py, epics.py,
work_item_properties.py, work_item_types.py.

Extends test_list_param_fix.py from 5 to 18 tests covering all newly
fixed parameters (JSON-string input and native-list regression cases).
@ej31
Copy link
Author

ej31 commented Mar 5, 2026

Following up on this fix — I noticed that the same serialization issue affects several more parameters beyond the four covered here.

Additional parameters that were missing the guard:

File Function Parameter
work_items.py create_work_item assignees, labels
work_items.py update_work_item assignees, labels
modules.py create_module members
modules.py update_module members
work_item_relations.py create_work_item_relation issues
epics.py create_epic assignees, labels
epics.py update_epic assignees, labels
work_item_properties.py create_work_item_property default_value
work_item_properties.py update_work_item_property default_value
work_item_types.py create_work_item_type project_ids
work_item_types.py update_work_item_type project_ids

I also backfilled the four guards introduced here with proper json.JSONDecodeError handling so that a malformed string raises a clear ValueError rather than an unhandled exception.

The changes (including 18 unit tests, up from 5) are on the same branch: fix/list-param-json-string-deserialization in the fork. Happy to open a separate PR or add the commits here, whichever is preferred.

@ej31 ej31 changed the base branch from main to canary March 5, 2026 05:16
@ej31
Copy link
Author

ej31 commented Mar 5, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
plane_mcp/tools/modules.py (1)

85-92: Consider extracting a shared coercion helper for JSON-list params.

This exact try/except block is duplicated multiple times in this file and across the tool modules. A helper will reduce drift and keep validation/error wording consistent.

♻️ Refactor sketch
+def _coerce_str_list_param(value: list[str] | None, param_name: str) -> list[str] | None:
+    if isinstance(value, str):
+        try:
+            value = json.loads(value)
+        except json.JSONDecodeError as e:
+            raise ValueError(
+                f"{param_name} must be a JSON array string or a list, got: {value!r}"
+            ) from e
+    if value is not None and (
+        not isinstance(value, list) or any(not isinstance(item, str) for item in value)
+    ):
+        raise ValueError(f"{param_name} must be a list[str] or a JSON array string of strings")
+    return value

Also applies to: 169-176, 246-253

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plane_mcp/tools/modules.py` around lines 85 - 92, Extract the duplicated
try/except JSON-array coercion into a reusable helper like
parse_json_list(value, param_name) that accepts the raw value and parameter
name, returns a list when given a list or a JSON array string, and raises
ValueError with the same message format ("{param_name} must be a JSON array
string or a list, got: {value!r}") when decoding fails; replace each inline
block that checks isinstance(members, str) (and the other duplicated blocks)
with calls to this helper (e.g., members = parse_json_list(members, "members"))
to centralize behavior and error wording across plane_mcp/tools/modules.py.
tests/test_list_param_fix.py (2)

4-7: Native-list coverage is inconsistent with the suite description.

Line 4-Line 7 says both JSON-string and native-list paths are verified, but only add_work_items_to_module has a native-list test (Line 64-Line 87). Consider parameterizing key tests to run both input forms consistently.

Also applies to: 64-87, 89-423

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_list_param_fix.py` around lines 4 - 7, The test suite claims to
verify both JSON-string and native-list inputs but only
`add_work_items_to_module` currently covers native lists; update tests in
tests/test_list_param_fix.py so the primary list-accepting test cases (including
`add_work_items_to_module` and the other tests between the noted ranges) are
parametrized to run twice: once with a native Python list and once with a
JSON-encoded string of that list. Implement this by adding a pytest
parameterization or a small helper/fixture that yields both representations for
each list-like argument, then reuse that helper in the test functions to ensure
assertions and mock expectations accept both forms (so conversion logic is
exercised consistently across all tests).

37-423: Add explicit malformed-JSON tests for the new ValueError contract.

The implementation now maps decode failures to ValueError, but this suite only tests valid JSON strings. Please add at least one invalid-input assertion per parsing surface (or a parametrized matrix) so the new error behavior can’t regress silently.

Suggested test additions (example pattern)
+import pytest
+
+@patch("plane_mcp.tools.modules.get_plane_client_context")
+def test_add_work_items_to_module_invalid_json_raises_value_error(mock_ctx):
+    mock_client = make_mock_client()
+    mock_ctx.return_value = (mock_client, "test-workspace")
+
+    mcp = FastMCP("test")
+    register_module_tools(mcp)
+    tool_fn = mcp._tool_manager._tools["add_work_items_to_module"].fn
+
+    with pytest.raises(ValueError, match="issue_ids must be a JSON array string or a list"):
+        tool_fn(project_id="proj-1", module_id="mod-1", issue_ids='["bad-json"')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_list_param_fix.py` around lines 37 - 423, The test suite currently
exercises valid JSON strings but omits negative tests for the new
decode-to-ValueError contract; add tests that pass malformed JSON (e.g.
'{"bad":') for each parsing surface and assert a ValueError is raised and the
underlying mock client method is NOT invoked. For each existing test pattern use
the same setup (mock get_plane_client_context, create FastMCP, register_*_tools)
and retrieve the tool function via mcp._tool_manager._tools["<tool_name>"].fn
(e.g. "add_work_items_to_module", "create_work_item", "update_module",
"create_work_item_relation", "create_epic", "create_work_item_property",
"create_work_item_type", etc.), wrap the call in pytest.raises(ValueError), and
assert the corresponding mock_client.*.<method>.assert_not_called() to ensure
malformed input short-circuits before calling the client.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plane_mcp/tools/work_item_relations.py`:
- Around line 77-84: After decoding issues, validate its shape: ensure issues is
a list and every element is a string, otherwise raise a ValueError with a clear
message; do this right after the json.loads branch (and also when issues is
already a list) so the rest of the function and SDK models receive a guaranteed
list[str] (refer to the issues variable and the json.loads handling in
work_item_relations.py).

In `@tests/test_list_param_fix.py`:
- Around line 299-337: Add tests in tests/test_list_param_fix.py mirroring
test_create_epic_assignees_json_string and
test_update_epic_assignees_json_string but for the labels field: call
create_epic and update_epic with labels=json.dumps(LABEL_IDS) (or appropriate
constant), assert mock_client.work_items.create.call_args.kwargs["data"].labels
== LABEL_IDS and mock_client.work_items.update.call_args.kwargs["data"].labels
== LABEL_IDS; reuse the same mocking pattern (mock_client, mock_ctx return,
FastMCP/register_epic_tools, and retrieving tool functions
create_epic/update_epic) so the new tests validate JSON-encoded labels are
parsed the same way as assignees.

---

Nitpick comments:
In `@plane_mcp/tools/modules.py`:
- Around line 85-92: Extract the duplicated try/except JSON-array coercion into
a reusable helper like parse_json_list(value, param_name) that accepts the raw
value and parameter name, returns a list when given a list or a JSON array
string, and raises ValueError with the same message format ("{param_name} must
be a JSON array string or a list, got: {value!r}") when decoding fails; replace
each inline block that checks isinstance(members, str) (and the other duplicated
blocks) with calls to this helper (e.g., members = parse_json_list(members,
"members")) to centralize behavior and error wording across
plane_mcp/tools/modules.py.

In `@tests/test_list_param_fix.py`:
- Around line 4-7: The test suite claims to verify both JSON-string and
native-list inputs but only `add_work_items_to_module` currently covers native
lists; update tests in tests/test_list_param_fix.py so the primary
list-accepting test cases (including `add_work_items_to_module` and the other
tests between the noted ranges) are parametrized to run twice: once with a
native Python list and once with a JSON-encoded string of that list. Implement
this by adding a pytest parameterization or a small helper/fixture that yields
both representations for each list-like argument, then reuse that helper in the
test functions to ensure assertions and mock expectations accept both forms (so
conversion logic is exercised consistently across all tests).
- Around line 37-423: The test suite currently exercises valid JSON strings but
omits negative tests for the new decode-to-ValueError contract; add tests that
pass malformed JSON (e.g. '{"bad":') for each parsing surface and assert a
ValueError is raised and the underlying mock client method is NOT invoked. For
each existing test pattern use the same setup (mock get_plane_client_context,
create FastMCP, register_*_tools) and retrieve the tool function via
mcp._tool_manager._tools["<tool_name>"].fn (e.g. "add_work_items_to_module",
"create_work_item", "update_module", "create_work_item_relation", "create_epic",
"create_work_item_property", "create_work_item_type", etc.), wrap the call in
pytest.raises(ValueError), and assert the corresponding
mock_client.*.<method>.assert_not_called() to ensure malformed input
short-circuits before calling the client.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 54b7f291-b116-42ee-a879-f619b2c9f79d

📥 Commits

Reviewing files that changed from the base of the PR and between e18a2b4 and 3353556.

📒 Files selected for processing (9)
  • plane_mcp/tools/cycles.py
  • plane_mcp/tools/epics.py
  • plane_mcp/tools/milestones.py
  • plane_mcp/tools/modules.py
  • plane_mcp/tools/work_item_properties.py
  • plane_mcp/tools/work_item_relations.py
  • plane_mcp/tools/work_item_types.py
  • plane_mcp/tools/work_items.py
  • tests/test_list_param_fix.py

After each json.loads() guard, validate that the decoded value is
actually a list of strings. Valid non-array JSON (e.g. "{}", "42",
"\"id\"") would otherwise pass the JSONDecodeError check silently and
fail later with an unclear error from the SDK or Pydantic.

Required params (issue_ids, issues): raise ValueError immediately if
the decoded value is not a list[str].

Optional params (assignees, labels, members, project_ids,
default_value): raise ValueError when the param is not None and not
a valid list[str].

Also adds two missing tests for create_epic/update_epic labels
parameter (JSON-encoded string), and fixes two pre-existing lint
issues in tests/:
- tests/test_integration.py: bare except -> except Exception
- tests/test_oauth_security.py: unsorted import block
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
plane_mcp/tools/modules.py (1)

85-97: Consider extracting shared JSON-list coercion to a helper.

The same parsing/validation block is repeated several times here (and in sibling tool modules), which makes future behavior drift likely.

♻️ Refactor sketch
+def _coerce_list_str_param(value: list[str] | str | None, param_name: str) -> list[str] | None:
+    if isinstance(value, str):
+        try:
+            value = json.loads(value)
+        except json.JSONDecodeError as e:
+            raise ValueError(
+                f"{param_name} must be a JSON array string or a list, got: {value!r}"
+            ) from e
+    if value is not None and (not isinstance(value, list) or any(not isinstance(i, str) for i in value)):
+        raise ValueError(f"{param_name} must be a list[str] or a JSON array string of strings")
+    return value
+
-        if isinstance(members, str):
-            try:
-                members = json.loads(members)
-            except json.JSONDecodeError as e:
-                raise ValueError(
-                    f"members must be a JSON array string or a list, got: {members!r}"
-                ) from e
-        if members is not None and (
-            not isinstance(members, list) or any(not isinstance(i, str) for i in members)
-        ):
-            raise ValueError("members must be a list[str] or a JSON array string of strings")
+        members = _coerce_list_str_param(members, "members")

Also applies to: 173-185, 254-263

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plane_mcp/tools/modules.py` around lines 85 - 97, Extract the repeated
JSON-string-to-list coercion/validation into a single helper function (e.g.,
parse_str_list or coerce_members_to_list) in plane_mcp.tools.modules that
accepts the raw members value, returns a list[str] or raises ValueError, and
encapsulates the try/json.loads + type checks; replace the inline blocks that
inspect/JSON-decode `members` (the occurrences around the shown diff and the
similar blocks at the other occurrences) to call this helper instead; update any
sibling tool modules to import and reuse this helper so all callers use the same
parsing/validation logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/test_integration.py`:
- Around line 47-48: The except block currently catches all exceptions when
parsing JSON (around the json.loads call handling content.text) which is too
broad; change the error handling to catch only json.JSONDecodeError and
TypeError (i.e., replace "except Exception:" with "except (json.JSONDecodeError,
TypeError):") so only expected parsing/typing errors fall back to returning
{"raw": content.text}; ensure json is imported and the handling is applied in
the function that calls json.loads with content.text.

---

Nitpick comments:
In `@plane_mcp/tools/modules.py`:
- Around line 85-97: Extract the repeated JSON-string-to-list
coercion/validation into a single helper function (e.g., parse_str_list or
coerce_members_to_list) in plane_mcp.tools.modules that accepts the raw members
value, returns a list[str] or raises ValueError, and encapsulates the
try/json.loads + type checks; replace the inline blocks that inspect/JSON-decode
`members` (the occurrences around the shown diff and the similar blocks at the
other occurrences) to call this helper instead; update any sibling tool modules
to import and reuse this helper so all callers use the same parsing/validation
logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 53ba0fd6-2a98-4e47-a73e-d4c228865061

📥 Commits

Reviewing files that changed from the base of the PR and between 3353556 and ac034c7.

📒 Files selected for processing (11)
  • plane_mcp/tools/cycles.py
  • plane_mcp/tools/epics.py
  • plane_mcp/tools/milestones.py
  • plane_mcp/tools/modules.py
  • plane_mcp/tools/work_item_properties.py
  • plane_mcp/tools/work_item_relations.py
  • plane_mcp/tools/work_item_types.py
  • plane_mcp/tools/work_items.py
  • tests/test_integration.py
  • tests/test_list_param_fix.py
  • tests/test_oauth_security.py
💤 Files with no reviewable changes (1)
  • tests/test_oauth_security.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_list_param_fix.py

Replace broad `except Exception` with `except (json.JSONDecodeError, TypeError)`
to avoid masking unrelated failures during integration debugging.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Alegrowin added a commit to Alegrowin/plane-mcp-server that referenced this pull request Mar 7, 2026
Pages (new methods):
- list_workspace_pages / list_project_pages (with pagination)
- update_workspace_page / update_project_page (partial updates via PATCH)
- delete_workspace_page / delete_project_page

Uses plane-sdk internal HTTP methods (_get, _patch, _delete) since
the SDK's Pages resource class doesn't expose list/update/delete yet.
Handles both paginated dict and plain list API responses.

Cherry-picked from upstream PR makeplane#76 (ej31):
- Fix JSON-encoded string handling for list parameters in MCP tools
- Affects cycles, epics, milestones, modules, work_items,
  work_item_properties, work_item_relations, work_item_types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bot-prodromou
Copy link

Hey @ej31 — just realized we independently hit the same issue and opened #79 with a broader fix covering all 16 affected functions across 8 files. We're closing ours since yours was first and correctly targets canary.

Your follow-up comment already identified the additional parameters. Here's the full list we found, in case it's helpful for expanding your PR:

File Functions Parameters
work_items.py create_work_item, update_work_item assignees, labels
epics.py create_epic, update_epic assignees, labels
modules.py create_module, update_module members
work_item_relations.py create_work_item_relation issues
work_item_properties.py create_work_item_property, update_work_item_property default_value, options
work_item_types.py create_work_item_type, update_work_item_type project_ids

We also extracted the guard into a shared utility (deserialize_list_param() in plane_mcp/utils/serialization.py) to avoid repeating the isinstance/json.loads pattern in every function. Happy to open a follow-up PR with that if you'd prefer to keep yours scoped to the original 4 functions.

Our branch with the full implementation is at nprodromou:fix/array-param-serialization if you want to cherry-pick anything.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants