wavetermdev/waveterm · error

build output is not executable

Error message

build output is not executable

What it means

After locating the build output, the controller verifies the file has an execute permission bit (info.Mode()&0111) on non-Windows platforms. This literal error means the built binary exists but is not executable — the build produced a non-executable artifact or lost its permission bits.

Source

Thrown at pkg/buildercontroller/buildercontroller.go:260

	})

	for _, line := range outputCapture.GetLines() {
		bc.outputBuffer.AddLine(line)
	}

	if err != nil {
		bc.handleBuildError(fmt.Errorf("build failed: %w", err), resultCh)
		return
	}

	info, err := os.Stat(cachePath)
	if err != nil {
		bc.handleBuildError(fmt.Errorf("build output not found: %w", err), resultCh)
		return
	}

	if runtime.GOOS != "windows" && info.Mode()&0111 == 0 {
		bc.handleBuildError(fmt.Errorf("build output is not executable"), resultCh)
		return
	}

	process, err := bc.runBuilderApp(ctx, appId, cachePath, builderEnv)
	if err != nil {
		bc.handleBuildError(fmt.Errorf("failed to run app: %w", err), resultCh)
		return
	}

	bc.lock.Lock()
	bc.process = process
	bc.setStatus_nolock(BuilderStatus_Running, process.Port, 0, "")
	bc.lock.Unlock()

	time.Sleep(1 * time.Second)

	if resultCh != nil {
		buildOutput := ""

View on GitHub (pinned to a4447c1563)

Solutions

  1. chmod +x the binary and rebuild to confirm the pipeline sets exec bits
  2. Verify TsunamiBuildInternal actually produced an executable (not an archive) at cachePath
  3. Check the cache directory filesystem preserves permission bits
  4. Fix the build step to chmod 0755 the output after MoveFileBack

Example fix

// before
// build leaves output with 0644
// after
os.Chmod(cachePath, 0o755) // in build step before returning from TsunamiBuildInternal
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(binPath)
if err == nil && runtime.GOOS != "windows" && info.Mode()&0111 == 0 {
    os.Chmod(binPath, 0o755)
}

Try / catch

if err := runBuild(appId); err != nil {
    if strings.Contains(err.Error(), "not executable") { os.Chmod(cachePath, 0o755) }
}

Prevention

When it happens

Trigger: os.Stat succeeds but Mode()&0111 == 0 on linux/darwin — e.g. the output is a data file, the chmod step of the build was skipped, or the file was copied in a way that dropped the exec bit.

Common situations: Build pipeline change emits a bundle/archive instead of a binary; file moved over a filesystem that drops permissions (some network mounts, FAT/exFAT); manual copy of build output.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/02b94efb893e6b7b. Report an issue: GitHub.