termux/termux-app · error · JSONException

An key in the extra-key matrix must be a string or an object

Error message

An key in the extra-key matrix must be a string or an object

What it means

Thrown by ExtraKeysInfo.normalizeKeyConfig when an element in the extra-key matrix is neither a JSON String nor a JSONObject. The matrix is expected to be an array of arrays where each cell is a plain string (auto-wrapped to {"key": value}) or an object. Any other JSON type (number, boolean, array, null) is rejected.

Source

Thrown at termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysInfo.java:188

            }
        }

        return buttons;
    }

    /**
     * Convert "value" -> {"key": "value"}. Required by
     * {@link ExtraKeyButton#ExtraKeyButton(JSONObject, ExtraKeyButton, ExtraKeysConstants.ExtraKeyDisplayMap, ExtraKeysConstants.ExtraKeyDisplayMap)}.
     */
    private static JSONObject normalizeKeyConfig(Object key) throws JSONException {
        JSONObject jobject;
        if (key instanceof String) {
            jobject = new JSONObject();
            jobject.put(ExtraKeyButton.KEY_KEY_NAME, key);
        } else if (key instanceof JSONObject) {
            jobject = (JSONObject) key;
        } else {
            throw new JSONException("An key in the extra-key matrix must be a string or an object");
        }
        return jobject;
    }

    public ExtraKeyButton[][] getMatrix() {
        return mButtons;
    }

    @NonNull
    public static ExtraKeysConstants.ExtraKeyDisplayMap getCharDisplayMapForStyle(String style) {
        switch (style) {
            case "arrows-only":
                return EXTRA_KEY_DISPLAY_MAPS.ARROWS_ONLY_CHAR_DISPLAY;
            case "arrows-all":
                return EXTRA_KEY_DISPLAY_MAPS.LOTS_OF_ARROWS_CHAR_DISPLAY;
            case "all":
                return EXTRA_KEY_DISPLAY_MAPS.FULL_ISO_CHAR_DISPLAY;
            case "none":

View on GitHub (pinned to 3df69d1da1)

Solutions

  1. Ensure every cell in the matrix is either a quoted string or a JSON object.
  2. Quote key names that look numeric or boolean (e.g. use "1" not 1).
  3. Run the JSON through a validator and fix type mismatches in the matrix.

Example fix

// before (invalid: numeric cell)
[["CTRL", 1], ["ALT", "TAB"]]

// after (string cell)
[["CTRL", "1"], ["ALT", "TAB"]]
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(key instanceof String) && !(key instanceof JSONObject)) {
    throw new JSONException("Matrix cell must be a string or object, got: "
        + (key == null ? "null" : key.getClass().getSimpleName()));
}

Type guard

private static boolean isValidKeyCell(Object key) {
    return key instanceof String || key instanceof JSONObject;
}

Try / catch

try {
    normalizeKeyConfig(cell);
} catch (JSONException e) {
    if (e.getMessage() != null && e.getMessage().contains("must be a string or an object")) {
        // coerce/quote the value or drop the cell
        cell = String.valueOf(cell);
    } else throw e;
}

Prevention

When it happens

Trigger: The extra-keys JSON matrix contains a numeric literal (e.g. 1), a boolean (true), null, or a nested array where a button cell is expected: [["CTRL", 1], ...].

Common situations: Hand-editing the matrix and putting a number/boolean instead of a key name; malformed JSON where a key name lost its quotes; templating bug inserting a non-string token.

Related errors


AI-assisted analysis of termux/termux-app@3df69d1da1 (2026-08-13). Data as JSON: /api/errors/1ad92714a0a14fe6. Report an issue: GitHub.