Docs menu

E088: A name you used belongs to another module, which did not mark it pub

What compiler error E088 means, and how to fix it.

Example
// util.trpub fn api(): int { return helper() + 1; }fn helper(): int { return 41; }// main.trimport util;fn main(): int {    return util::helper();    // ERROR: Function 'helper' is private to module 'util'.    //   Note: 'helper' is declared in module 'util' without `pub`    //   Hint: If 'helper' is meant to be used from other modules, mark    //   it `pub` in util.tr: `pub fn helper(...)`. Otherwise, 'util'    //   offers these public functions: api.}

Everything a module declares at its top level – functions, structs, enums, errors, machines, extern fns – is private to that module unless it is written with pub (or public, the same word). Another module can only use the pub ones. That keeps a module’s helpers free to change, and makes its public surface something you can read off the file.

The error appears however the private name is reached:

Example
util::helper()               // a qualified callmut h: util::Hidden = ...;   // a type annotationutil::Hidden::default()      // constructing a private structutil::HiddenColor::A         // a variant of a private enumimport util::helper;         // asking for it by nameimport util::[api, helper];  // ...in a list

Members of a pub type are checked the same way – a struct’s fields and methods are private to its module unless written pub, even when the struct itself is pub:

Example
// shapes.trpub struct Point { pub x: int, pub y: int, cache: int }pub fn Point.len(): int { ... }fn Point.refresh(): void { ... }// main.trp.x            // ok: a `pub` fieldp.cache        // ERROR: Field 'Point.cache' is private to module 'shapes'.p.len()        // ok: a `pub` methodp.refresh()    // ERROR: Method 'Point.refresh' is private to module 'shapes'.Point::default()   // always fine -- it only zero-fills, so it cannot                   // break an invariant that zero cannot

For a private field the hint names the type’s public methods, because that is usually how the data is meant to be reached: List.data is a raw pointer, so l.data[0] says to use get, set, length and the rest instead.

Call syntax cannot get around it. p.secret_twice() resolves through “uniform function call syntax” to a free function secret_twice(p) – and a free function another module did not mark pub is not a candidate there.

A [*] import (import util::[*];) is different: it just skips the private names, so it never raises this error, and a private name in util can never clash with one of your own.

There are two ways to fix it, and the hint offers both:

  1. The module is yours and the name is meant to be shared: add pub to the
Example
declaration in the module's own file --    pub fn helper(): int { return 41; }
  1. The name is an implementation detail of somebody else’s module: use what
Example
the module does offer. The hint lists its `pub` functions or types.

Two things that are NOT errors, because they never cross a module boundary: a module using its own private names (api() above calling helper()), and a pub generic – function or struct method – whose body uses a private helper or a private field: when you instantiate it from your own file, the copy is still checked as the module that wrote it.

export immut constants are always public: export is their pub.

Run turf --explain E088 in a terminal to read this again.

Last updated: Oct 15, 2026Edit this page on GitHub

Esc

Type to search.