FuelLabs/fuels-ts · error · FuelError
WORKSPACE_NOT_DETECTED
WORKSPACE_NOT_DETECTED
Error message
Forc workspace not detected in:
${workspace}/Forc.toml
Try using '${swayProgramType}s' instead of 'workspace' in:
${configPath} What it means
Thrown during config resolution when fuels.config.ts declares a `workspace` but the Forc.toml at that workspace path has no `[workspace]` section. The loader reads the manifest, sees no workspace members, and tells you the path points at a single Sway program (contract/script/predicate) rather than a workspace.
Source
Thrown at packages/fuels/src/cli/config/loadConfig.ts:100
if (!userConfig.workspace) {
// Resolve members individually
const { contracts, predicates, scripts } = userConfig;
config.contracts = (contracts || []).map((c: string) => resolve(cwd, c));
config.scripts = (scripts || []).map((s: string) => resolve(cwd, s));
config.predicates = (predicates || []).map((p: string) => resolve(cwd, p));
} else {
// Resolve members via workspace
const workspace = resolve(cwd, userConfig.workspace);
const forcToml = readForcToml(workspace);
if (!forcToml.workspace) {
const workspaceMsg = `Forc workspace not detected in:\n ${workspace}/Forc.toml`;
const swayProgramType = readSwayType(workspace);
const exampleMsg = `Try using '${swayProgramType}s' instead of 'workspace' in:\n ${configPath}`;
throw new FuelError(
FuelError.CODES.WORKSPACE_NOT_DETECTED,
[workspaceMsg, exampleMsg].join('\n\n')
);
}
const swayMembers = forcToml.workspace.members.map((member) => resolve(workspace, member));
swayMembers
.map((path) => ({ path, type: readSwayType(path) }))
.filter(({ type }) => type !== SwayType.library)
.forEach(({ path, type }) => config[`${type as Exclude<SwayType, 'library'>}s`].push(path));
config.workspace = workspace;
}
return config;
}
View on GitHub (pinned to b3f37c91ac)
Solutions
- Switch the config key from `workspace` to the matching plural key (`contracts`, `scripts`, or `predicates`) — the error message tells you the detected type.
- Or restructure the program into a real Forc workspace with a `[workspace] members = [...]` section.
Example fix
// before — Forc.toml has [contract], not [workspace]
export default createConfig({ workspace: './my-contract' });
// after
export default createConfig({ contracts: ['./my-contract'] }); Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
function isWorkspace(path: string): boolean {
if (!existsSync(join(path, 'Forc.toml'))) return false;
return /\[workspace\]/.test(readFileSync(join(path, 'Forc.toml'), 'utf8'));
} Type guard
const isWorkspaceConfig = (cfg: unknown): cfg is { workspace: string } =>
!!cfg && typeof cfg === 'object' && typeof (cfg as any).workspace === 'string'; Prevention
- Use `workspace:` only when Forc.toml has a [workspace] section.
- For single programs, use contracts/scripts/predicates instead.
- After restructuring, audit fuels.config.ts keys against the manifest.
When it happens
Trigger: Setting `workspace: './path'` in fuels.config.ts where ./path/Forc.toml describes a single program (it has `[contract]`/`[script]`/`[predicate]`, not `[workspace]`).
Common situations: Configuring a single program as a workspace, copied config from a workspace template into a single-program repo, refactored a workspace down to one program without updating config.
Related errors
- CONFIG_FILE_NOT_FOUND
- CONFIG_FILE_ALREADY_EXISTS
- CONFIG_FILE_NOT_FOUND
- BIN_FILE_NOT_FOUND
- Contract not found!
AI-assisted analysis of FuelLabs/fuels-ts@b3f37c91ac (2026-08-12).
Data as JSON: /api/errors/c784e4430e576a07.
Report an issue: GitHub.