dagger/dagger · error

marshal introspection schema for self-call merge: %w

Error message

marshal introspection schema for self-call merge: %w

What it means

When no IntrospectionJSON was provided by the engine (generate-module against live introspection), the schema in hand is marshaled to the introspection.Response JSON the schema tool expects; a json.Marshal failure of that struct is wrapped here. This is a defensive wrap — json.Marshal on these structs essentially only fails on unsupported types.

Source

Thrown at cmd/codegen/generator/go/generate_module.go:154

		if slices.Contains(schema.DependencyNames(), moduleName) {
			return nil, fmt.Errorf(
				"a dependency is installed under the module's own name %q; "+
					"self-calls need distinct names — reinstall the dependency under "+
					"another name (dagger install --name)", moduleName)
		}
		emitter := templates.NewModuleIntrospectionEmitter(ctx, schema, schemaVersion, g.Config, pkg, fset)
		moduleTypesJSON, err := emitter.ModuleIntrospectionJSON(moduleName)
		if err != nil {
			return nil, fmt.Errorf("emit module types for self-call merge: %w", err)
		}
		// The engine's codegen path always passes --introspection-json-path,
		// but generate-module can also run against live introspection; in that
		// case rebuild the JSON the schema tool needs from the schema in hand.
		depsJSON := g.Config.IntrospectionJSON
		if depsJSON == "" {
			data, err := json.Marshal(introspection.Response{Schema: schema, SchemaVersion: schemaVersion})
			if err != nil {
				return nil, fmt.Errorf("marshal introspection schema for self-call merge: %w", err)
			}
			depsJSON = string(data)
		}
		merged, err := g.Config.Dag.
			Schema(dagger.JSON(depsJSON)).
			Merge(dagger.JSON(moduleTypesJSON), moduleName).
			Contents(ctx)
		if err != nil {
			return nil, fmt.Errorf("merge module types into schema: %w", err)
		}
		var resp introspection.Response
		if err := json.Unmarshal([]byte(merged), &resp); err != nil {
			return nil, fmt.Errorf("unmarshal merged introspection JSON: %w", err)
		}
		schema = resp.Schema
		generator.SetSchemaParents(schema)
		generator.SetSchema(schema)
	}

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Upgrade or align dagger.io/dagger SDK and CLI versions so introspection.Response marshals correctly
  2. Pass --introspection-json-path (engine codegen path) so Config.IntrospectionJSON is set and marshal is skipped
  3. Inspect the wrapped json error's field name and patch/upgrade the offending schema type
Defensive patterns

Strategy: try-catch

Validate before calling

// prefer the engine path so IntrospectionJSON is provided:
// run codegen through the CLI with --introspection-json-path instead of live introspection
if introspectionJSONPath == "" {
    log.Println("no introspection JSON provided; schema will be re-marshaled (upgrade SDK if this fails)")
}

Try / catch

if _, err := g.GenerateModule(ctx, schema, schemaVersion); err != nil {
    if strings.Contains(err.Error(), "marshal introspection schema") {
        log.Fatalf("introspection.Response unmarshalable — align SDK/CLI versions: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: g.Config.IntrospectionJSON == "" and json.Marshal(introspection.Response{Schema: schema, SchemaVersion: schemaVersion}) fails — requires an unmarshalable value inside the schema (custom MarshalJSON returning invalid data, channel/func field).

Common situations: Running the generate-module path with live introspection on a schema/version combination where introspection.Response or a schema field gained a non-JSON-serializable member (SDK/library version mismatch).

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/057615931b9cff60. Report an issue: GitHub.