wavetermdev/waveterm · error

static files not available before app initialization; use Ap

Error message

static files not available before app initialization; use AppInit to access files during initialization

What it means

ReadStaticFile reads from the app's embedded static filesystem, which is attached to the default client only after app initialization completes. Calling it earlier (StaticFS is nil) returns this error directing you to AppInit, where static files are accessible during initialization.

Source

Thrown at tsunami/app/defaultclient.go:219

		secretDesc = meta.Desc
		secretOptional = meta.Optional
	}
	client.DeclareSecret(secretName, secretDesc, secretOptional)
	return os.Getenv(secretName)
}

func PrintAppManifest() {
	client := engine.GetDefaultClient()
	client.PrintAppManifest()
}

// ReadStaticFile reads a file from the embedded static filesystem.
// The path MUST start with "static/" (e.g., "static/config.json").
// Returns the file contents or an error if the file doesn't exist or can't be read.
func ReadStaticFile(path string) ([]byte, error) {
	client := engine.GetDefaultClient()
	if client.StaticFS == nil {
		return nil, errors.New("static files not available before app initialization; use AppInit to access files during initialization")
	}
	if !strings.HasPrefix(path, "static/") {
		return nil, fmt.Errorf("ReadStaticFile path must start with 'static/': %w", fs.ErrNotExist)
	}
	// Strip "static/" prefix since the FS is already sub'd to the static directory
	relativePath := strings.TrimPrefix(path, "static/")
	return fs.ReadFile(client.StaticFS, relativePath)
}

// OpenStaticFile opens a file from the embedded static filesystem.
// The path MUST start with "static/" (e.g., "static/config.json").
// Returns an fs.File or an error if the file doesn't exist or can't be opened.
func OpenStaticFile(path string) (fs.File, error) {
	client := engine.GetDefaultClient()
	if client.StaticFS == nil {
		return nil, errors.New("static files not available before app initialization; use AppInit to access files during initialization")
	}
	if !strings.HasPrefix(path, "static/") {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Move the ReadStaticFile call after app initialization completes (post-AppInit).
  2. If you need files during initialization, read them inside the AppInit callback where StaticFS is available.
  3. Ensure the app's startup path actually populates StaticFS before dependent code runs.
  4. For pure-asset needs, use embed.FS directly in your package instead of the app client.
  5. Add a startup ordering guard/assert that StaticFS is set before consumers run.

Example fix

// before
func init() {
    data, _ := app.ReadStaticFile("static/config.json") // too early
}
// after
func OnInit(ctx context.Context) error {
    data, err := app.ReadStaticFile("static/config.json") // inside AppInit
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

if client.StaticFS == nil {
    return nil, fmt.Errorf("static FS not ready; call from AppInit or later")
}

Try / catch

data, err := app.ReadStaticFile("static/config.json")
if err != nil {
    return fmt.Errorf("read static config: %w", err)
}

Prevention

When it happens

Trigger: Calling tsunami/app.ReadStaticFile(path) before the app's initialization finished — engine.GetDefaultClient() returns a client whose StaticFS field is still nil (outside or early in AppInit).

Common situations: Reading static config assets at package init time; accessing embedded files in constructors that run before AppInit; tests that call ReadStaticFile without booting the app.

Related errors


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