github/copilot-sdk · error

failed to write license

Error message

failed to write license: %w

What it means

extractCLILicense scans a .tgz tarball for a package/LICENSE.md or package/LICENSE entry and streams it to disk via extractFileFromTarballStream. This error wraps any failure from that write step: the output file could not be created, or the copy/close of its contents failed. The wrapped error identifies the underlying OS or stream problem.

Solutions

  1. Ensure outputDir exists and is writable (mkdir -p and check permissions / run with correct user)
  2. Check the destination license path is not a directory and no permission conflicts exist
  3. Free disk space if ENOSPC is reported
  4. Rerun the bundler; inspect the wrapped error for the root cause

Example fix

// before
if err := extractCLILicense(tarballPath, outputDir); err != nil { return err }
// after
if err := os.MkdirAll(outputDir, 0o755); err != nil { return fmt.Errorf("output dir: %w", err) }
if err := extractCLILicense(tarballPath, outputDir); err != nil { return err }
Defensive patterns

Strategy: try-catch

Validate before calling

if info, err := os.Stat(outputDir); err != nil || !info.IsDir() { os.MkdirAll(outputDir, 0o755) }
if info, err := os.Stat(outputDir); err != nil || !info.IsDir() || unix.Access(outputDir, unix.W_OK) != nil { return fmt.Errorf("output dir not writable: %s", outputDir) }

Type guard

func dirWritable(dir string) bool { p := filepath.Join(dir, ".probe"); if err := os.WriteFile(p, nil, 0o644); err != nil { return false }; os.Remove(p); return true }

Try / catch

if err := extractCLILicense(tarballPath, outputDir); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) { log.Printf("license write failed at %s: %v", pe.Path, pe.Err) }
    return fmt.Errorf("license extraction failed: %w", err)
}

Prevention

When it happens

Trigger: extractCLILicense is called (from buildBundle) with an outputDir that is unwritable, nonexistent, has wrong permissions, or where the destination license name collides with a directory; also on stream read failures mid-copy from the tar reader.

Common situations: Running the bundler as a user without write access to the output directory; output directory deleted or never created before bundling; disk full during license extraction; destination path exists as a directory named LICENSE.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/5541bee70a02d912. Report an issue: GitHub.

Appendix: source

Thrown at go/cmd/bundler/main.go:1110

	if err != nil {
		return fmt.Errorf("failed to create gzip reader: %w", err)
	}
	defer gzReader.Close()

	tarReader := tar.NewReader(gzReader)
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("failed to read tar: %w", err)
		}
		switch header.Name {
		case "package/LICENSE.md", "package/LICENSE":
			licenseName := filepath.Base(licensePath)
			if err := extractFileFromTarballStream(tarReader, outputDir, licenseName, os.FileMode(header.Mode)); err != nil {
				return fmt.Errorf("failed to write license: %w", err)
			}
			return nil
		}
	}

	return fmt.Errorf("license file not found in tarball")
}

func licensePathForOutput(outputPath string) string {
	if strings.HasSuffix(outputPath, ".zst") {
		return strings.TrimSuffix(outputPath, ".zst") + ".license"
	}
	return outputPath + ".license"
}

func licenseFileName(binaryName string) string {
	if strings.HasSuffix(binaryName, ".zst") {
		return strings.TrimSuffix(binaryName, ".zst") + ".license"

View on GitHub (pinned to cd8cf15dc3)