LaurieWired/GhidraMCP · warning

Base type not found for " + typeName + ", defaulting to void

Error message

Base type not found for " + typeName + ", defaulting to void*

What it means

This is not a thrown exception but a warning logged via Msg.warn inside GhidraMCPPlugin's type-parsing helper. When a type name like 'Foo*' requires a base type, the plugin looks up the base type with findDataTypeByNameInAllCategories; if the lookup fails, it logs this warning and silently substitutes a void* pointer instead of failing the operation. It exists so struct/pointer parsing from decompiler output never hard-fails, at the cost of producing a possibly wrong type.

Solutions

  1. Define or import the missing base type into the program's Data Type Manager (or attach the GDT archive containing it) before re-running the tool, so findDataTypeByNameInAllCategories resolves it.
  2. Verify the exact type name spelling/case; the lookup is by name across categories, so a mismatched or qualified name ('myLib::Foo' vs 'Foo') will miss — create the type under a category the search covers.
  3. If the base type genuinely cannot be provided, accept the void* fallback and retype members manually in the resulting structure.
  4. Extend findDataTypeByNameInAllCategories or the parsing code to also check built-in/arch default type catalogs before falling back.

Example fix

// before
DataType baseType = findDataTypeByNameInAllCategories(dtm, baseTypeName);
if (baseType != null) {
    return new PointerDataType(baseType);
}
Msg.warn(this, "Base type not found for " + typeName + ", defaulting to void*");
return new PointerDataType(dtm.getDataType("/void"));
// after
DataType baseType = findDataTypeByNameInAllCategories(dtm, baseTypeName);
if (baseType == null) {
    baseType = dtm.getDataType("/" + baseTypeName); // direct root-path lookup
}
if (baseType != null) {
    return new PointerDataType(baseType);
}
Msg.warn(this, "Base type not found for " + typeName + ", defaulting to void*");
return new PointerDataType(dtm.getDataType("/void"));
Defensive patterns

Strategy: validation

Validate before calling

// Ghidra scripting / client-side pre-check before invoking the MCP tool
Transaction tx = null;
try {
    DataType dt = currentProgram.getDataTypeManager().getDataType("/MyStruct");
    if (dt == null) {
        throw new IllegalStateException(
            "Base type 'MyStruct' is not in the Data Type Manager; " +
            "define it or load the containing .gdt archive first.");
    }
    // safe to call the tool now
} finally {
    if (tx != null) end;
}

Type guard

function hasBaseType(program, baseTypeName) {
    return program.getDataTypeManager().getAllDataTypes().stream()
        .anyMatch(dt -> dt.getName().equals(baseTypeName));
}

Prevention

When it happens

Trigger: Calling any plugin endpoint that parses a type string (e.g. decompiler or struct-related HTTP endpoints) where the string contains a pointer type 'BaseType*' (or the type appears in the pointer-parsing branch) and 'BaseType' cannot be resolved by findDataTypeByNameInAllCategories in the program's data type manager — e.g. the struct is defined only in the decompiler output but was never imported into the program.

Common situations: Analyzing binaries where the decompiler emits pointers to types that don't exist in the Ghidra data type manager (custom structs, types from a missing/incompatible GDT archive, or a typo in a user-supplied type name passed to an MCP tool); users then see structures generated with void* members instead of the expected typed pointers.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of LaurieWired/GhidraMCP@27f316f801 (2026-09-10). Data as JSON: /api/errors/c46ed12184d589d9. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/com/lauriewired/GhidraMCPPlugin.java:1445

            return dataType;
        }

        // Check for Windows-style pointer types (PXXX)
        if (typeName.startsWith("P") && typeName.length() > 1) {
            String baseTypeName = typeName.substring(1);

            // Special case for PVOID
            if (baseTypeName.equals("VOID")) {
                return new PointerDataType(dtm.getDataType("/void"));
            }

            // Try to find the base type
            DataType baseType = findDataTypeByNameInAllCategories(dtm, baseTypeName);
            if (baseType != null) {
                return new PointerDataType(baseType);
            }

            Msg.warn(this, "Base type not found for " + typeName + ", defaulting to void*");
            return new PointerDataType(dtm.getDataType("/void"));
        }

        // Handle common built-in types
        switch (typeName.toLowerCase()) {
            case "int":
            case "long":
                return dtm.getDataType("/int");
            case "uint":
            case "unsigned int":
            case "unsigned long":
            case "dword":
                return dtm.getDataType("/uint");
            case "short":
                return dtm.getDataType("/short");
            case "ushort":
            case "unsigned short":
            case "word":

View on GitHub (pinned to 27f316f801)