Skip to content

fix: support versioned select option schemas#15

Merged
barryw merged 2 commits into
barryw:mainfrom
johnnybravo-xyz:fix/select-options-schema
Jul 12, 2026
Merged

fix: support versioned select option schemas#15
barryw merged 2 commits into
barryw:mainfrom
johnnybravo-xyz:fix/select-options-schema

Conversation

@johnnybravo-xyz

@johnnybravo-xyz johnnybravo-xyz commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

The bug

paperless_custom_fields_create and paperless_custom_fields_update fail with
UPSTREAM_ERROR / HTTP 400 when sending bare-string select options to
paperless-ngx v2.14 or later. Paperless returns:

{"select_options": ["'str' object has no attribute 'get'"]}

Root cause

The select-option wire format changed in paperless-ngx v2.14:

  • Before v2.14, extra_data.select_options is a list of strings.
  • In v2.14 and later, each option is an object containing label and an
    optional stable id.

The MCP previously modeled every option as a string, so modern Paperless
attempted to call .get() on a string and rejected the request.

The fix

  • Model select options as SelectOption records containing id and
    label.
  • Accept both legacy string responses and modern object responses, normalizing
    them to objects for MCP clients.
  • Detect the Paperless version through api/status/ and serialize request
    options as strings before v2.14 or objects on v2.14 and later.
  • Preserve existing option IDs during updates so Paperless does not treat
    unchanged options as removed and clear assigned document values.
  • Update fixtures and add request-payload coverage for modern create, legacy
    create, modern ID-preserving update, and legacy update.

Verification

  • Live create originally verified against paperless-ngx v2.20.15.
  • dotnet build -c Release --no-restore: 0 errors, 0 warnings.
  • Focused custom-field/client tests: 53 passed.
  • Full test suite: 150 passed.

Backward compatibility

Both Paperless wire formats are supported. Pre-v2.14 servers continue receiving
string lists, while v2.14+ servers receive object lists. Modern option IDs are
returned to MCP clients and retained across updates.

johnnybravo-xyz and others added 2 commits July 3, 2026 17:40
Paperless-ngx v2.14+ requires each entry in extra_data.select_options
to be a JSON object with a 'label' key. Serialising as bare strings
(List<string>) triggers "'str' object has no attribute 'get'" in
paperless's serialisers.py, surfaced through this MCP as
UPSTREAM_ERROR / HTTP 400.

Introduce a SelectOption record with a Label property that serialises
to {"label": "..."}. Change CustomFieldExtraData.SelectOptions
from List<string> to List<SelectOption>. Update both call sites in
CustomFieldTools.cs (Create + Update) to wrap the split values.

Verified against paperless-ngx v2.20.15: creating a select field with
23 options now returns 200; without the fix it returned 400.
Keep stable option IDs during updates to avoid clearing assigned values. Serialize the pre-2.14 string shape when required and accept both response formats.
@barryw barryw changed the title fix: select options must be object list, not bare strings fix: support versioned select option schemas Jul 12, 2026
@barryw barryw merged commit f7b3f6e into barryw:main Jul 12, 2026
1 check passed
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