{"record":{"id":"402d569ba5bf9de3","repo":"hankcs/HanLP","slug":"output-must-be-of-type-bool-or-str","errorCode":null,"errorMessage":"output ({}) must be of type bool or str","messagePattern":"output \\((.+?)\\) must be of type bool or str","errorType":"validation","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"hanlp/common/keras_component.py","lineNumber":73,"sourceCode":"            name = 'evaluate'\n        if save_dir and not logger:\n            logger = init_logger(name=name, root_dir=save_dir, level=logging.INFO if verbose else logging.WARN,\n                                 mode='w')\n        tst_data = self.transform.file_to_dataset(input_path, batch_size=batch_size)\n        samples = self.num_samples_in(tst_data)\n        num_batches = math.ceil(samples / batch_size)\n        if warm_up:\n            for x, y in tst_data:\n                self.model.predict_on_batch(x)\n                break\n        if output:\n            assert save_dir, 'Must pass save_dir in order to output'\n            if isinstance(output, bool):\n                output = os.path.join(save_dir, name) + '.predict' + ext\n            elif isinstance(output, str):\n                output = output\n            else:\n                raise RuntimeError('output ({}) must be of type bool or str'.format(repr(output)))\n        timer = Timer()\n        eval_outputs = self.evaluate_dataset(tst_data, callbacks, output, num_batches, **kwargs)\n        loss, score, output = eval_outputs[0], eval_outputs[1], eval_outputs[2]\n        delta_time = timer.stop()\n        speed = samples / delta_time.delta_seconds\n\n        if logger:\n            f1: IOBES_F1_TF = None\n            for metric in self.model.metrics:\n                if isinstance(metric, IOBES_F1_TF):\n                    f1 = metric\n                    break\n            extra_report = ''\n            if f1:\n                overall, by_type, extra_report = f1.state.result(full=True, verbose=False)\n                extra_report = ' \\n' + extra_report\n            logger.info('Evaluation results for {} - '\n                        'loss: {:.4f} - {} - speed: {:.2f} sample/sec{}'","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/hankcs/HanLP/blob/ddb1299bddff079e447af52ec12549c50636bfa8/hanlp/common/keras_component.py#L55-L91","documentation":"build_criterion on Word2VecEmbedding always raises NotImplementedError because a static pretrained embedding has no loss function. Loss/criterion construction only makes sense for trainable task components in HanLP's Component API.","triggerScenarios":"Any code path that calls build_criterion on a Word2VecEmbedding, e.g. a generic trainer iterating over components and unconditionally building criteria, or calling .fit() on the embedding.","commonSituations":"Running a generic training pipeline over a config whose model is only an embedding; migrating training code from a task model to a pure embedding module.","solutions":["Train a task component and use Word2VecEmbedding as its embedding layer","Skip criterion-building for embedding modules (check isinstance before calling)","Override build_criterion in a subclass if custom behavior is required"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"assert not isinstance(model, Word2VecEmbedding), 'build_criterion unsupported for embeddings'","typeGuard":"def supports_criterion(c) -> bool:\n    return c.__class__.build_criterion is not Word2VecEmbedding.build_criterion","tryCatchPattern":"try:\n    criterion = model.build_criterion()\nexcept NotImplementedError:\n    criterion = None  # inference-only component","preventionTips":["Gate criterion building on component capability","Use task models as training entry points"],"tags":["hanlp","criterion","embedding","not-implemented"],"backgroundTag":"not-implemented-error","analyzedSha":"ddb1299bddff079e447af52ec12549c50636bfa8","analyzedAt":"2026-08-27T03:36:54.287Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}