Skip to content

Diagnostics

Every problem Clarive HCL reports carries a stable code. Codes are append-only: a retired code is never recycled for a different meaning.

cla-objects/prod/generic_server.web01.hcl:4:11: error[HCL017]: Bare identifier 'bastion' used as a value -- did you mean the string "bastion" or a reference like resource.<class>.<name>?
  4 |   proxy = bastion
    |           ^

file:line:column: severity[CODE]: message, then the source line and a caret. An item with no position renders as file: severity[CODE]: message. Tabs in the context line become single spaces so the caret lands under the right column.

Two severities: error and warning. Errors refuse whatever was being done; warnings are reported and the work continues. A run collects at most 200 items so a pathological file cannot spin out megabytes of output.

Codes are grouped by the stage that raises them.

Range Stage Raised by
HCL0xx lexer and parser reading the text
HCL1xx encoder cla export, the UI encode endpoints
HCL2xx decoder, catalog, resolver, plan, apply cla import, import-plan, diff, the UI save endpoints
HCL3xx rules anywhere a rule block is read or written

Lexer — HCL001 to HCL005

Code Severity Message
HCL001 error Unexpected character %1
Unexpected character %1 -- HCL strings use double quotes (for ')
Unexpected character %1 -- HCL has no backtick strings, use a heredoc (for `)
Unexpected character %1 -- HCL statements end at the end of the line (for ;)
Unexpected character %1 -- only meaningful inside a quoted string or heredoc (for $, @, \, &)
HCL002 error Unterminated string, a quoted string cannot span lines
Unterminated string, missing closing %1
HCL003 error Unterminated heredoc, missing closing %1
HCL004 error Unterminated block comment, missing %1
HCL005 error Invalid escape sequence %1 in string

On an unexpected character the lexer reports once per line and resyncs to the end of that line.

Parser — HCL010 to HCL020

Code Severity Message
HCL010 error Block %1 has %2 labels, a block takes at most two
HCL011 error Block label %1 must be a quoted string
HCL012 error Expected %1 to open the body of block %2, found %3
HCL013 error Unclosed block %1 opened at line %2, expected %3
HCL014 error Unexpected %1 at the top level of the file
Unexpected %1, expected an attribute or a block
Unexpected %1, expected a value
Expected an identifier after %1, found %2
Unclosed call to %1, expected %2
Expected %1 or %2 in the arguments of %3, found %4
Expected %1 or %2 in list, found %3
HCL015 error Expected %1 or a block body after %2, found %3
HCL016 error Expected end of line after the value of %1, found %2
Expected end of line after block %1, found %2
HCL017 error Bare identifier %1 used as a value -- did you mean the string %2 or a reference like %3?
HCL018 error Unclosed list opened at line %1, expected %2
HCL019 error Unclosed object opened at line %1, expected %2
Expected an object key, found %1
Expected %1 or %2 after object key %3, found %4
Expected %1 or %2 in object, found %3
HCL020 error Unsupported HCL construct: conditional expression -- Clarive HCL v1 does not evaluate expressions
Unsupported HCL construct: operator %1 -- ...
Unsupported HCL construct: unary operator %1 -- ...
Unsupported HCL construct: parenthesised expression -- ...
Unsupported HCL construct: %1 expression -- ... (for)
Unsupported HCL construct: index access -- reference Clarive objects by address instead
Unsupported HCL construct: splat expression -- list every reference explicitly
HCL020 error Unsupported HCL construct: %1 block -- Clarive HCL v1 does not generate blocks (dynamic)

Every parser diagnostic is an error. HCL010 and the dynamic form of HCL020 are the two that do not abort the construct being parsed — the offending labels or block are kept in the tree and parsing continues — but they still refuse the run like any other error.

The parser resyncs to the next newline at the current brace depth, so an error inside one block is contained to that block. Any parse error makes the whole tree untrustworthy — nothing downstream of one is ever written.

See Syntax for the complete list of refused constructs.

Encoder — HCL100 to HCL112

Code Severity Message
HCL100 warning Skipped an object of family %1 because it has no name to build a label from
HCL101 warning No encoder for family %1 yet
HCL102 warning Dropped a reference to %1 because it could not be resolved
HCL103 warning Dropped a reference to %1 because class %2 is internal
HCL104 error Cannot encrypt secrets: no cipher available. Use %1 instead
HCL105 — reserved; defined but never raised
HCL106 warning Refused to write %1 for %2: it is a database id and no address could be found for it
Refused to write %1 for %2: it is a list of database ids and they will not mean the same thing elsewhere
HCL107 warning The value of %1 has %2 written inside it. That is a database id and it will not mean the same thing elsewhere
HCL110 warning Skipped the topic %1 because its category could not be named
HCL111 warning Field %1 is stored on topics of %2 but the category form does not define it, so it is written as raw
HCL112 warning Dropped a reference to topic %1 because its category is not in %2

HCL104 is the only encoder error and it exits cla export with 2. It fires only when the selection actually contains a sensitive attribute — an encrypt-mode export of a secret-free selection exits 0 silently.

HCL106 means an attribute was not written. Read the export summary: a grant that lost a bound this way is narrower on the target than it was on the source.

HCL107 is the one leak the id gate cannot close. A mid written inside a Perl body, a saved JSON condition or a YAML stash is one opaque string to the encoder. Warning is the honest answer: refusing would delete somebody's code over a substring, and rewriting it would be a guess the import could not undo. Reported once per distinct id per export.

Decoder — HCL200 to HCL219, HCL222 and HCL223

Code Severity Message
HCL200 error Unknown block type %1
HCL201 error Block type %1 is not supported yet
HCL202 error Block %1 needs a name label
HCL203 error A resource block needs a class label and a name label
HCL204 warning Ignored %1 on a user block: imports never touch credentials
HCL205 warning Attribute %1 is not declared by %2 and will be stored as is
HCL206 error Attribute %1 expects references, not a literal
HCL207 error Unknown function %1
HCL208 error Function %1 needs one argument
HCL209 error Cannot decode %1: no secret key given. Pass %2
HCL210 error Cannot decode %1: wrong key, or the value is not encrypted
HCL211 error A %1 block needs a %2 attribute (moved, to)
HCL212 error A %1 block needs an %2 attribute (removed, at)
HCL213 error Block %1 is not allowed inside %2, only rules hold blocks like this
HCL214 error Write this as %1, not as a resource -- it is not administered like one
HCL215 error A topic block needs a category label and a name label
HCL216 error Attribute %1 does not belong at the top of a topic block, put it in %2
HCL217 error Block %1 is not allowed inside a topic, only %2 and %3 are
HCL218 error %1 must be a map, like %2 -- variables, one of its environments, a _natures, or a nature override (Variables)
HCL219 warning Ignored the grants of user %1: a user in groups takes its grants from them
HCL222 error Write group membership on each user, as %1, not as %2 on the group
HCL223 error Attribute %1 lists user groups, and %2 is not one

HCL222 and HCL223 sit outside the decoder's range because HCL220 and HCL221 were already taken by the catalog, and codes are never renumbered once they ship. HCL219, HCL222 and HCL223 are all about who holds a user's permissions.

HCL205 is silenced entirely by --lax, for files written by an installation with attributes this one has never heard of. Unknown blocks are still refused.

HCL205 and HCL213 are not raised for role, user or group blocks: those families decode without a schema check, so an unknown attribute is accepted and then quietly discarded by the apply step. See Roles, users and groups.

Catalog, resolver, plan, apply — HCL220 to HCL253

Code Severity Message
HCL220 error Cannot read %1: %2
HCL221 error Duplicate address %1, already declared at %2
HCL230 error, or warning under --allow-missing Unresolved reference %1 in %2
HCL240 warning Nothing to remove at %1, it is already gone
HCL250 error Refusing to apply: the plan has conflicts or errors
HCL251 error Failed to apply %1: %2
HCL252 error Failed to link references for %1: %2
HCL253 error Failed to delete %1: %2

HCL221 usually means the same object was declared twice, often once in each spelling. The first declaration wins.

Under --allow-missing, HCL230 becomes a warning and the depending object is marked SKIPPED. The skip is contagious.

HCL251, HCL252 and HCL253 are apply failures. They exit 3, and the run reports exactly what was applied and what was not. There is no rollback.

Rules — HCL300 to HCL321

Code Severity Message
HCL300 warning Skipped a rule node with no operation key
HCL301 error Not a rule block: %1
HCL302 error A rule block needs a name label
HCL303 warning Unknown rule attribute %1
HCL304 error Unknown rule operation %1
HCL305 error Cannot read the condition %1
HCL306 error Unknown function %1
HCL307 error Function %1 needs one argument
HCL308 error Cannot decode %1: no secret key given. Pass %2
HCL309 error Cannot decode %1: wrong key, or the value is not encrypted
HCL310 error No rule block found in this file
HCL311 error Write exactly one step here
HCL312 error Nested steps are edited in the rule tree
HCL313 error The operation cannot change here: this step is %1
HCL320 error the Perl compiler's own message, on the offending line
HCL321 error This step does not compile: %1

HCL306 to HCL309 are the rule-body mirror of HCL207 to HCL210.

HCL310 is only raised by the UI rule editor, where a file with no rule block in it is a mistake rather than an empty file.

HCL311 to HCL313 are raised only by the HCL tab of the Rule Designer's operation dialog, which edits one step on its own. The tab holds exactly one block and no top-level attributes (HCL311). The step's children stay in the rule tree, so a nested block is refused rather than silently dropped (HCL312). The operation itself is fixed by the node being edited (HCL313): the text may pick another form of the same operation, such as sh running locally or remotely, but not turn an if into a foreach.

HCL320 is the embedded-Perl syntax check. The parser treats a perl/perl_code body (or a perl_for, and a foreach with in_perl) as opaque text, so the UI rule editor compiles each Perl block on its own and reports the compiler's real message on the HCL line that holds it. It is raised only for a caller that may modify rules — compiling Perl runs its BEGIN/use, which is a write-level capability, not a read-only one — so a view-only validate never triggers it.

HCL321 comes from saving a rule in the UI rule editor. A text can parse, decode and pass HCL320 and still make a rule that does not compile — an IF condition's Perl, for one, is not a body HCL320 compiles. The rule compiler then refuses the save, and Perl counts its line numbers in the code generated from the whole rule, which is nowhere on screen. So the compile is repeated with every step marked with the HCL line it was written on, and each error is reported on the line of the step it came from, in Perl's own words. The compiler's full message is kept beside it.

HCL304 is worth singling out: the node is dropped and the rest of the rule imports. The most common cause is not a typo but the keyword inversion gap described in Rules.

Diagnostics::code_title does not know every code

The in-code catalogue covers HCL000–HCL107 and HCL300–HCL313. The HCL110–HCL112 and HCL200–HCL253 ranges ship and are emitted, but are absent from that table, so code_title returns nothing for them and codes() omits them. The messages themselves are unaffected; only a caller enumerating codes programmatically will see the gap.

HCL000

The fallback when a caller raises a diagnostic without a code. It has no title. Seeing it means a code was forgotten at the call site.