NationalSecurityAgency/ghidra · error · LSHException

Trying to insert on read-only database

Error message

Trying to insert on read-only database

What it means

`fdbDatabaseInsert` checks `info.readonly` at entry. If the connection was opened read-only, any insert is rejected with LSHException before any work begins. Read-only mode is intended for query-only clients; writes are refused outright.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/AbstractSQLFunctionDatabase.java:1937

			response.result.add(simres);

			simres.transfer(response.manage, true);
		}

		return vecToResultMap.size();
	}

	/**
	 * Entry point for the InsertRequest command
	 * @param query the query to execute
	 * @throws LSHException if trying to insert into a read-only database
	 * @throws SQLException if there is an error issuing the query
	 * @throws DatabaseNonFatalException if there are duplicate executables and/or functions
	 */
	private void fdbDatabaseInsert(InsertRequest query)
			throws LSHException, SQLException, DatabaseNonFatalException {
		if (info.readonly) {
			throw new LSHException("Trying to insert on read-only database");
		}
		if (FunctionDatabase.checkSettingsForInsert(query.manage, info)) { // Check if settings are valid and is this is first insert
			info.major = query.manage.getMajorVersion();
			info.minor = query.manage.getMinorVersion();
			info.settings = query.manage.getSettings();
			keyValueTable.writeBasicInfo(info); // Save off the settings associated with this first insert
		}
		ResponseInsert response = query.insertresponse;
		if ((query.repo_override != null) && (query.repo_override.length() != 0)) {
			query.manage.overrideRepository(query.repo_override, query.path_override);
		}
		insert(query.manage);
		response.numexe = query.manage.getExecutableRecordSet().size();
		response.numfunc = query.manage.numFunctions();
	}

	/**
	 * Entry point for the QueryInfo command

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Open the connection without the read-only flag.
  2. Use a separate, read-write connection/client for insert operations.
  3. Verify the connection's readonly setting before dispatching InsertRequest.

Example fix

// before: readonly connection used for ingest
info.readonly = true;  db.insert(query);   // throws
// after: writable connection for writes
info.readonly = false; db.insert(query);
Defensive patterns

Strategy: validation

Validate before calling

// Guard inserts against a read-only connection.
if (db.getInfo().readonly) {
    throw new IllegalStateException(
        "Cannot insert on a read-only connection; open read-write");
}

Try / catch

try {
    db.insert(query);
} catch (LSHException e) {
    if (e.getMessage().equals("Trying to insert on read-only database")) {
        // operator must use a read-write connection -- do not retry as-is
        throw new ConnectionModeException("Reopen the DB read-write for inserts", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Opening a BSim DB connection in read-only mode (e.g. for similarity queries) and then dispatching an InsertRequest against it.

Common situations: Misconfigured connection URL/flags; reusing a query-only client for ingest; a DB role restricted to read; a deliberate read-only replica used accidentally for writes.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/365bf3153cce9957. Report an issue: GitHub.