siyuan-note/siyuan · error

Fields [mode] and [modeOS] must be provided together

Error message

Fields [mode] and [modeOS] must be provided together

What it means

The bazaar install endpoint accepts an optional legacy pairing of fields: mode (target type: 0 = app, 1 = frontend plugin context) and modeOS (OS-specific flag). These two must always be sent together; sending only one is ambiguous and rejected by the decoder. This preserves compatibility with older clients while enforcing a consistent contract.

Solutions

  1. Add the missing sibling field so both mode and modeOS are present in the same request.
  2. Remove both fields entirely if you do not need the legacy mode selection.
  3. Check the caller's payload-construction code to ensure it sets the pair atomically.
  4. Consult the current API contract docs for the correct mode/modeOS value pair.

Example fix

// before
{"packageName": "siyuan-plugin-x", "mode": 1}
// after
{"packageName": "siyuan-plugin-x", "mode": 1, "modeOS": false}
Defensive patterns

Strategy: validation

Validate before calling

const keys = Object.keys(payload);
if (keys.includes("mode") !== keys.includes("modeOS")) {
  throw new Error("mode and modeOS must be sent together");
}

Type guard

const hasBothOrNeither = (p) => (("mode" in p) === ("modeOS" in p));

Try / catch

try {
  await post("/api/bazaar", payload);
} catch (e) {
  if (String(e.message).includes("must be provided together")) {
    payload.modeOS = payload.modeOS ?? false;
    await post("/api/bazaar", payload);
  } else { throw e; }
}

Prevention

When it happens

Trigger: POSTing to the bazaar install endpoint with {"packageName":"x","mode":0} (missing modeOS) or {"packageName":"x","modeOS":false} (missing mode).

Common situations: Partial upgrades of client code where one field was added but its sibling wasn't, hand-written curl payloads copied from outdated docs, or plugin code that sets only modeOS to target a specific OS.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/39215cdad81ac5ce. Report an issue: GitHub.

Appendix: source

Thrown at kernel/apicontract/bazaar.go:916

		if request.Keyword, err = bazaarString(fields, "keyword", false, false); err != nil {
			return request, err
		}
		if request.RepoURL, err = bazaarString(fields, "repoURL", true, true); err != nil {
			return request, err
		}
		if request.RepoHash, err = bazaarString(fields, "repoHash", true, true); err != nil {
			return request, err
		}
		if request.RepoRef, err = bazaarString(fields, "repoRef", false, false); err != nil {
			return request, err
		}
		if request.PackageName, err = bazaarString(fields, "packageName", true, true); err != nil {
			return request, err
		}
		_, hasMode := fields["mode"]
		_, hasModeOS := fields["modeOS"]
		if hasMode != hasModeOS {
			return request, errors.New("Fields [mode] and [modeOS] must be provided together")
		}
		if hasMode {
			mode, parseErr := legacyField[float64](fields, "mode", "Number", true)
			if parseErr != nil {
				return request, parseErr
			}
			modeOS, parseErr := legacyField[bool](fields, "modeOS", "Boolean", true)
			if parseErr != nil {
				return request, parseErr
			}
			if mode != 0 && mode != 1 {
				return request, errors.New("Field [mode] must be 0 or 1")
			}
			request.Mode = &mode
			request.ModeOS = &modeOS
		}
		return request, nil
	}

View on GitHub (pinned to 9f775e8a12)