dagger/dagger · error

SDK module %q has no source

Error message

SDK module %q has no source

What it means

Thrown by installedSDKSourceForModule in core/schema/workspace_sdk.go when a module entry matched as an SDK (by key or as-sdk name) has an empty effective source: moduleEntrySourceWithPin(entry) (source + optional @pin) returns "". An SDK install must point at a module source (local path or git ref with pin); without one Dagger cannot resolve where the SDK's module lives.

Source

Thrown at core/schema/workspace_sdk.go:243

		}
		matches = append(matches, moduleName)
	}
	sort.Strings(matches)
	switch len(matches) {
	case 0:
		return "", workspace.ModuleEntry{}, "", fmt.Errorf("%q is not installed as an SDK in this workspace; run `dagger sdk install %s` first", name, name)
	case 1:
		entry := cfg.Modules[matches[0]]
		return installedSDKSourceForModule(matches[0], entry)
	default:
		return "", workspace.ModuleEntry{}, "", fmt.Errorf("SDK name %q is ambiguous: matches modules.%s.as-sdk; choose a unique as-sdk.name", name, strings.Join(matches, ".as-sdk, modules."))
	}
}

func installedSDKSourceForModule(moduleName string, entry workspace.ModuleEntry) (string, workspace.ModuleEntry, string, error) {
	source := moduleEntrySourceWithPin(entry)
	if source == "" {
		return "", workspace.ModuleEntry{}, "", fmt.Errorf("SDK module %q has no source", moduleName)
	}
	return moduleName, entry, source, nil
}

func moduleEntrySourceWithPin(entry workspace.ModuleEntry) string {
	return sourceWithPin(entry.Source, entry.Pin)
}

func resolvedModuleEntrySourceWithPin(configDir string, entry workspace.ModuleEntry) string {
	return sourceWithPin(workspace.ResolveModuleEntrySource(configDir, entry.Source), entry.Pin)
}

func moduleEntrySourceWithPinRelativeTo(configDir, targetDir string, entry workspace.ModuleEntry) (string, error) {
	if !workspace.IsLocalRef(entry.Source, "") {
		return moduleEntrySourceWithPin(entry), nil
	}
	source := workspace.ResolveModuleEntrySource(configDir, entry.Source)
	rel, err := filepath.Rel(targetDir, source)

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Add the missing `source` field to the module entry in dagger.json (local path or remote ref).
  2. Re-run `dagger sdk install <name>` so Dagger rewrites the entry with a proper source and pin.
  3. Restore the source value from version control (git diff/checkout dagger.json) if a merge or edit dropped it.
  4. Remove the broken entry entirely if it is stale, then reinstall the SDK.

Example fix

// before (dagger.json)
{ "modules": { "my-sdk": { "as-sdk": { "name": "my-sdk" } } } }

// after (dagger.json)
{ "modules": { "my-sdk": { "source": "modules/my-sdk", "pin": "abc123...", "as-sdk": { "name": "my-sdk" } } } }
Defensive patterns

Strategy: validation

Validate before calling

import "encoding/json"

func sdkEntryHasSource(daggerJSONPath, sdkName string) error {
  raw, err := os.ReadFile(daggerJSONPath)
  if err != nil { return err }
  var cfg struct {
    Modules map[string]struct {
      Source string `json:"source"`
    } `json:"modules"`
  }
  if err := json.Unmarshal(raw, &cfg); err != nil { return err }
  e, ok := cfg.Modules[sdkName]
  if !ok { return fmt.Errorf("entry %q missing", sdkName) }
  if e.Source == "" { return fmt.Errorf("entry %q has empty source", sdkName) }
  return nil
}

Type guard

func entryHasSource(e ModuleEntry) bool { return e.Source != "" }

Try / catch

mod, entry, src, err := installedSDKSourceForModule(moduleName, entry)
if err != nil && strings.Contains(err.Error(), "has no source") {
  return fmt.Errorf("reinstall %q to populate source: `dagger sdk install %s`", moduleName, moduleName)
}

Prevention

When it happens

Trigger: installedSDKSource resolves a name to a workspace.ModuleEntry whose `source` field is empty or unset (and no pin can make it non-empty), e.g. a dagger.json modules entry that only contains an as-sdk block with no source path.

Common situations: Hand-editing dagger.json and adding an SDK/module entry with only a name but no `source`; tooling or a merge that dropped the source field; an entry scaffolded by a script that expected source to be filled in later; corrupt or truncated dagger.json.

Related errors


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